blob: fe878b05f78c231770068aeae2ccea61903524c5 [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
Karl Wiberg918f50c2018-07-05 11:40:33 +020024#include "absl/memory/memory.h"
Steve Antondcc3c022017-12-22 16:02:54 -080025#include "pc/test/fakeaudiocapturemodule.h"
Steve Antonfa2260d2017-12-28 16:38:23 -080026#include "pc/test/fakesctptransport.h"
Steve Antondcc3c022017-12-22 16:02:54 -080027#include "rtc_base/gunit.h"
Steve Antondcc3c022017-12-22 16:02:54 -080028#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() {
Karl Wiberg918f50c2018-07-05 11:40:33 +020066 return absl::make_unique<FakeSctpTransportFactory>();
Steve Antonfa2260d2017-12-28 16:38:23 -080067 }
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());
Karl Wiberg918f50c2018-07-05 11:40:33 +020091 auto observer = absl::make_unique<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
Yves Gerey4e933292018-10-31 15:36:05 +010098 observer->SetPeerConnectionInterface(pc.get());
Karl Wiberg918f50c2018-07-05 11:40:33 +020099 return absl::make_unique<PeerConnectionWrapper>(pc_factory, pc,
100 std::move(observer));
Steve Antondcc3c022017-12-22 16:02:54 -0800101 }
102
103 std::unique_ptr<rtc::VirtualSocketServer> vss_;
104 rtc::AutoSocketServerThread main_;
Steve Antondcc3c022017-12-22 16:02:54 -0800105};
106
107// Tests for JSEP initial offer generation.
108
109// Test that an offer created by a PeerConnection with no transceivers generates
110// no media sections.
111TEST_F(PeerConnectionJsepTest, EmptyInitialOffer) {
112 auto caller = CreatePeerConnection();
Steve Antonfa2260d2017-12-28 16:38:23 -0800113
Steve Antondcc3c022017-12-22 16:02:54 -0800114 auto offer = caller->CreateOffer();
Steve Antonfa2260d2017-12-28 16:38:23 -0800115 ASSERT_EQ(0u, offer->description()->contents().size());
Steve Antondcc3c022017-12-22 16:02:54 -0800116}
117
118// Test that an initial offer with one audio track generates one audio media
119// section.
120TEST_F(PeerConnectionJsepTest, AudioOnlyInitialOffer) {
121 auto caller = CreatePeerConnection();
122 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
Steve Antondcc3c022017-12-22 16:02:54 -0800123
Steve Antonfa2260d2017-12-28 16:38:23 -0800124 auto offer = caller->CreateOffer();
Steve Antondcc3c022017-12-22 16:02:54 -0800125 auto contents = offer->description()->contents();
126 ASSERT_EQ(1u, contents.size());
127 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, contents[0].media_description()->type());
128}
129
130// Test than an initial offer with one video track generates one video media
131// section
132TEST_F(PeerConnectionJsepTest, VideoOnlyInitialOffer) {
133 auto caller = CreatePeerConnection();
134 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
Steve Antondcc3c022017-12-22 16:02:54 -0800135
Steve Antonfa2260d2017-12-28 16:38:23 -0800136 auto offer = caller->CreateOffer();
Steve Antondcc3c022017-12-22 16:02:54 -0800137 auto contents = offer->description()->contents();
138 ASSERT_EQ(1u, contents.size());
139 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, contents[0].media_description()->type());
140}
141
Steve Antonfa2260d2017-12-28 16:38:23 -0800142// Test that an initial offer with one data channel generates one data media
143// section.
144TEST_F(PeerConnectionJsepTest, DataOnlyInitialOffer) {
145 auto caller = CreatePeerConnection();
146 caller->CreateDataChannel("dc");
147
148 auto offer = caller->CreateOffer();
149 auto contents = offer->description()->contents();
150 ASSERT_EQ(1u, contents.size());
151 EXPECT_EQ(cricket::MEDIA_TYPE_DATA, contents[0].media_description()->type());
152}
153
154// Test that creating multiple data channels only results in one data section
155// generated in the offer.
156TEST_F(PeerConnectionJsepTest, MultipleDataChannelsCreateOnlyOneDataSection) {
157 auto caller = CreatePeerConnection();
158 caller->CreateDataChannel("first");
159 caller->CreateDataChannel("second");
160 caller->CreateDataChannel("third");
161
162 auto offer = caller->CreateOffer();
163 ASSERT_EQ(1u, offer->description()->contents().size());
164}
165
Steve Antondcc3c022017-12-22 16:02:54 -0800166// Test that multiple media sections in the initial offer are ordered in the
167// order the transceivers were added to the PeerConnection. This is required by
168// JSEP section 5.2.1.
169TEST_F(PeerConnectionJsepTest, MediaSectionsInInitialOfferOrderedCorrectly) {
170 auto caller = CreatePeerConnection();
171 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
172 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
173 RtpTransceiverInit init;
174 init.direction = RtpTransceiverDirection::kSendOnly;
175 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init);
Steve Antondcc3c022017-12-22 16:02:54 -0800176
Steve Antonfa2260d2017-12-28 16:38:23 -0800177 auto offer = caller->CreateOffer();
Steve Antondcc3c022017-12-22 16:02:54 -0800178 auto contents = offer->description()->contents();
179 ASSERT_EQ(3u, contents.size());
180
181 const MediaContentDescription* media_description1 =
182 contents[0].media_description();
183 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, media_description1->type());
184 EXPECT_EQ(RtpTransceiverDirection::kSendRecv,
185 media_description1->direction());
186
187 const MediaContentDescription* media_description2 =
188 contents[1].media_description();
189 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, media_description2->type());
190 EXPECT_EQ(RtpTransceiverDirection::kSendRecv,
191 media_description2->direction());
192
193 const MediaContentDescription* media_description3 =
194 contents[2].media_description();
195 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, media_description3->type());
196 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
197 media_description3->direction());
198}
199
200// Test that media sections in the initial offer have different mids.
201TEST_F(PeerConnectionJsepTest, MediaSectionsInInitialOfferHaveDifferentMids) {
202 auto caller = CreatePeerConnection();
203 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
204 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
Steve Antonfa2260d2017-12-28 16:38:23 -0800205
Steve Antondcc3c022017-12-22 16:02:54 -0800206 auto offer = caller->CreateOffer();
Steve Antondcc3c022017-12-22 16:02:54 -0800207 auto contents = offer->description()->contents();
208 ASSERT_EQ(2u, contents.size());
209 EXPECT_NE(contents[0].name, contents[1].name);
210}
211
212TEST_F(PeerConnectionJsepTest,
213 StoppedTransceiverHasNoMediaSectionInInitialOffer) {
214 auto caller = CreatePeerConnection();
215 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
216 transceiver->Stop();
217
218 auto offer = caller->CreateOffer();
219 EXPECT_EQ(0u, offer->description()->contents().size());
220}
221
222// Tests for JSEP SetLocalDescription with a local offer.
223
224TEST_F(PeerConnectionJsepTest, SetLocalEmptyOfferCreatesNoTransceivers) {
225 auto caller = CreatePeerConnection();
Steve Antonfa2260d2017-12-28 16:38:23 -0800226
Steve Antondcc3c022017-12-22 16:02:54 -0800227 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
228
229 EXPECT_THAT(caller->pc()->GetTransceivers(), ElementsAre());
230 EXPECT_THAT(caller->pc()->GetSenders(), ElementsAre());
231 EXPECT_THAT(caller->pc()->GetReceivers(), ElementsAre());
232}
233
234TEST_F(PeerConnectionJsepTest, SetLocalOfferSetsTransceiverMid) {
235 auto caller = CreatePeerConnection();
236 auto audio_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
237 auto video_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
238
239 auto offer = caller->CreateOffer();
240 std::string audio_mid = offer->description()->contents()[0].name;
241 std::string video_mid = offer->description()->contents()[1].name;
242
243 ASSERT_TRUE(caller->SetLocalDescription(std::move(offer)));
244
245 EXPECT_EQ(audio_mid, audio_transceiver->mid());
246 EXPECT_EQ(video_mid, video_transceiver->mid());
247}
248
249// Tests for JSEP SetRemoteDescription with a remote offer.
250
251// Test that setting a remote offer with sendrecv audio and video creates two
252// transceivers, one for receiving audio and one for receiving video.
253TEST_F(PeerConnectionJsepTest, SetRemoteOfferCreatesTransceivers) {
254 auto caller = CreatePeerConnection();
255 auto caller_audio = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
256 auto caller_video = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
257 auto callee = CreatePeerConnection();
258
259 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
260
261 auto transceivers = callee->pc()->GetTransceivers();
262 ASSERT_EQ(2u, transceivers.size());
Steve Anton1bc97162018-06-25 14:04:01 -0700263
Steve Anton69470252018-02-09 11:43:08 -0800264 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, transceivers[0]->media_type());
Steve Antondcc3c022017-12-22 16:02:54 -0800265 EXPECT_EQ(caller_audio->mid(), transceivers[0]->mid());
266 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly, transceivers[0]->direction());
Steve Anton1bc97162018-06-25 14:04:01 -0700267 EXPECT_EQ(0u, transceivers[0]->sender()->stream_ids().size());
268
Steve Anton69470252018-02-09 11:43:08 -0800269 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, transceivers[1]->media_type());
Steve Antondcc3c022017-12-22 16:02:54 -0800270 EXPECT_EQ(caller_video->mid(), transceivers[1]->mid());
271 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly, transceivers[1]->direction());
Steve Anton1bc97162018-06-25 14:04:01 -0700272 EXPECT_EQ(0u, transceivers[1]->sender()->stream_ids().size());
Steve Antondcc3c022017-12-22 16:02:54 -0800273}
274
275// Test that setting a remote offer with an audio track will reuse the
276// transceiver created for a local audio track added by AddTrack.
277// This is specified in JSEP section 5.10 (Applying a Remote Description). The
278// intent is to preserve backwards compatibility with clients who only use the
279// AddTrack API.
280TEST_F(PeerConnectionJsepTest, SetRemoteOfferReusesTransceiverFromAddTrack) {
281 auto caller = CreatePeerConnection();
282 caller->AddAudioTrack("a");
283 auto caller_audio = caller->pc()->GetTransceivers()[0];
284 auto callee = CreatePeerConnection();
285 callee->AddAudioTrack("a");
286
287 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
288
289 auto transceivers = callee->pc()->GetTransceivers();
290 ASSERT_EQ(1u, transceivers.size());
291 EXPECT_EQ(MediaStreamTrackInterface::kAudioKind,
292 transceivers[0]->receiver()->track()->kind());
293 EXPECT_EQ(caller_audio->mid(), transceivers[0]->mid());
294}
295
296// Test that setting a remote offer with an audio track marked sendonly will not
297// reuse a transceiver created by AddTrack. JSEP only allows the transceiver to
298// be reused if the offer direction is sendrecv or recvonly.
299TEST_F(PeerConnectionJsepTest,
300 SetRemoteOfferDoesNotReuseTransceiverIfDirectionSendOnly) {
301 auto caller = CreatePeerConnection();
302 caller->AddAudioTrack("a");
303 auto caller_audio = caller->pc()->GetTransceivers()[0];
304 caller_audio->SetDirection(RtpTransceiverDirection::kSendOnly);
305 auto callee = CreatePeerConnection();
306 callee->AddAudioTrack("a");
307
308 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
309
310 auto transceivers = callee->pc()->GetTransceivers();
311 ASSERT_EQ(2u, transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200312 EXPECT_EQ(absl::nullopt, transceivers[0]->mid());
Steve Antondcc3c022017-12-22 16:02:54 -0800313 EXPECT_EQ(caller_audio->mid(), transceivers[1]->mid());
314}
315
316// Test that setting a remote offer with an audio track will not reuse a
317// transceiver added by AddTransceiver. The logic for reusing a transceiver is
318// specific to those added by AddTrack and is tested above.
319TEST_F(PeerConnectionJsepTest,
320 SetRemoteOfferDoesNotReuseTransceiverFromAddTransceiver) {
321 auto caller = CreatePeerConnection();
322 caller->AddAudioTrack("a");
323 auto callee = CreatePeerConnection();
324 auto transceiver = callee->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
325
326 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
327
328 auto transceivers = callee->pc()->GetTransceivers();
329 ASSERT_EQ(2u, transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200330 EXPECT_EQ(absl::nullopt, transceivers[0]->mid());
Steve Antondcc3c022017-12-22 16:02:54 -0800331 EXPECT_EQ(caller->pc()->GetTransceivers()[0]->mid(), transceivers[1]->mid());
332 EXPECT_EQ(MediaStreamTrackInterface::kAudioKind,
333 transceivers[1]->receiver()->track()->kind());
334}
335
336// Test that setting a remote offer with an audio track will not reuse a
337// transceiver created for a local video track added by AddTrack.
338TEST_F(PeerConnectionJsepTest,
339 SetRemoteOfferDoesNotReuseTransceiverOfWrongType) {
340 auto caller = CreatePeerConnection();
341 caller->AddAudioTrack("a");
342 auto callee = CreatePeerConnection();
343 auto video_sender = callee->AddVideoTrack("v");
344
345 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
346
347 auto transceivers = callee->pc()->GetTransceivers();
348 ASSERT_EQ(2u, transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200349 EXPECT_EQ(absl::nullopt, transceivers[0]->mid());
Steve Antondcc3c022017-12-22 16:02:54 -0800350 EXPECT_EQ(caller->pc()->GetTransceivers()[0]->mid(), transceivers[1]->mid());
351 EXPECT_EQ(MediaStreamTrackInterface::kAudioKind,
352 transceivers[1]->receiver()->track()->kind());
353}
354
355// Test that setting a remote offer with an audio track will not reuse a
356// stopped transceiver.
357TEST_F(PeerConnectionJsepTest, SetRemoteOfferDoesNotReuseStoppedTransceiver) {
358 auto caller = CreatePeerConnection();
359 caller->AddAudioTrack("a");
360 auto callee = CreatePeerConnection();
361 callee->AddAudioTrack("a");
362 callee->pc()->GetTransceivers()[0]->Stop();
363
364 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
365
366 auto transceivers = callee->pc()->GetTransceivers();
367 ASSERT_EQ(2u, transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200368 EXPECT_EQ(absl::nullopt, transceivers[0]->mid());
Steve Antondcc3c022017-12-22 16:02:54 -0800369 EXPECT_TRUE(transceivers[0]->stopped());
370 EXPECT_EQ(caller->pc()->GetTransceivers()[0]->mid(), transceivers[1]->mid());
371 EXPECT_FALSE(transceivers[1]->stopped());
372}
373
374// Test that audio and video transceivers created on the remote side with
375// AddTrack will all be reused if there is the same number of audio/video tracks
376// in the remote offer. Additionally, this tests that transceivers are
377// successfully matched even if they are in a different order on the remote
378// side.
379TEST_F(PeerConnectionJsepTest, SetRemoteOfferReusesTransceiversOfBothTypes) {
380 auto caller = CreatePeerConnection();
381 caller->AddVideoTrack("v");
382 caller->AddAudioTrack("a");
383 auto callee = CreatePeerConnection();
384 callee->AddAudioTrack("a");
385 callee->AddVideoTrack("v");
386
387 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
388
389 auto caller_transceivers = caller->pc()->GetTransceivers();
390 auto callee_transceivers = callee->pc()->GetTransceivers();
391 ASSERT_EQ(2u, callee_transceivers.size());
392 EXPECT_EQ(caller_transceivers[0]->mid(), callee_transceivers[1]->mid());
393 EXPECT_EQ(caller_transceivers[1]->mid(), callee_transceivers[0]->mid());
394}
395
396// Tests for JSEP initial CreateAnswer.
397
398// Test that the answer to a remote offer creates media sections for each
399// offered media in the same order and with the same mids.
400TEST_F(PeerConnectionJsepTest, CreateAnswerHasSameMidsAsOffer) {
401 auto caller = CreatePeerConnection();
402 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
403 auto second_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
404 auto third_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
Steve Antonfa2260d2017-12-28 16:38:23 -0800405 caller->CreateDataChannel("dc");
Steve Antondcc3c022017-12-22 16:02:54 -0800406 auto callee = CreatePeerConnection();
407
Steve Antonfa2260d2017-12-28 16:38:23 -0800408 auto offer = caller->CreateOffer();
409 const auto* offer_data = cricket::GetFirstDataContent(offer->description());
410 ASSERT_TRUE(
411 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
412 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
Steve Antondcc3c022017-12-22 16:02:54 -0800413
414 auto answer = callee->CreateAnswer();
415 auto contents = answer->description()->contents();
Steve Antonfa2260d2017-12-28 16:38:23 -0800416 ASSERT_EQ(4u, contents.size());
Steve Antondcc3c022017-12-22 16:02:54 -0800417 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, contents[0].media_description()->type());
Steve Antonfa2260d2017-12-28 16:38:23 -0800418 EXPECT_EQ(first_transceiver->mid(), contents[0].name);
Steve Antondcc3c022017-12-22 16:02:54 -0800419 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, contents[1].media_description()->type());
Steve Antonfa2260d2017-12-28 16:38:23 -0800420 EXPECT_EQ(second_transceiver->mid(), contents[1].name);
Steve Antondcc3c022017-12-22 16:02:54 -0800421 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, contents[2].media_description()->type());
Steve Antonfa2260d2017-12-28 16:38:23 -0800422 EXPECT_EQ(third_transceiver->mid(), contents[2].name);
423 EXPECT_EQ(cricket::MEDIA_TYPE_DATA, contents[3].media_description()->type());
424 EXPECT_EQ(offer_data->name, contents[3].name);
Steve Antondcc3c022017-12-22 16:02:54 -0800425}
426
427// Test that an answering media section is marked as rejected if the underlying
428// transceiver has been stopped.
429TEST_F(PeerConnectionJsepTest, CreateAnswerRejectsStoppedTransceiver) {
430 auto caller = CreatePeerConnection();
431 caller->AddAudioTrack("a");
432 auto callee = CreatePeerConnection();
433
434 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
435
436 callee->pc()->GetTransceivers()[0]->Stop();
437
438 auto answer = callee->CreateAnswer();
439 auto contents = answer->description()->contents();
440 ASSERT_EQ(1u, contents.size());
441 EXPECT_TRUE(contents[0].rejected);
442}
443
444// Test that CreateAnswer will generate media sections which will only send or
445// receive if the offer indicates it can do the reciprocating direction.
446// The full matrix is tested more extensively in MediaSession.
447TEST_F(PeerConnectionJsepTest, CreateAnswerNegotiatesDirection) {
448 auto caller = CreatePeerConnection();
449 RtpTransceiverInit init;
450 init.direction = RtpTransceiverDirection::kSendOnly;
451 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init);
452 auto callee = CreatePeerConnection();
453 callee->AddAudioTrack("a");
454
455 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
456
457 auto answer = callee->CreateAnswer();
458 auto contents = answer->description()->contents();
459 ASSERT_EQ(1u, contents.size());
460 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
461 contents[0].media_description()->direction());
462}
463
464// Tests for JSEP SetLocalDescription with a local answer.
465// Note that these test only the additional behaviors not covered by
466// SetLocalDescription with a local offer.
467
468// Test that SetLocalDescription with an answer sets the current_direction
469// property of the transceivers mentioned in the session description.
470TEST_F(PeerConnectionJsepTest, SetLocalAnswerUpdatesCurrentDirection) {
471 auto caller = CreatePeerConnection();
472 auto caller_audio = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
473 caller_audio->SetDirection(RtpTransceiverDirection::kRecvOnly);
474 auto callee = CreatePeerConnection();
475 callee->AddAudioTrack("a");
476
477 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
478 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
479
480 auto transceivers = callee->pc()->GetTransceivers();
481 ASSERT_EQ(1u, transceivers.size());
482 // Since the offer was recvonly and the transceiver direction is sendrecv,
483 // the negotiated direction will be sendonly.
484 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
485 transceivers[0]->current_direction());
486}
487
488// Tests for JSEP SetRemoteDescription with a remote answer.
489// Note that these test only the additional behaviors not covered by
490// SetRemoteDescription with a remote offer.
491
492TEST_F(PeerConnectionJsepTest, SetRemoteAnswerUpdatesCurrentDirection) {
493 auto caller = CreatePeerConnection();
494 caller->AddAudioTrack("a");
495 auto callee = CreatePeerConnection();
496 callee->AddAudioTrack("a");
497 auto callee_audio = callee->pc()->GetTransceivers()[0];
498 callee_audio->SetDirection(RtpTransceiverDirection::kSendOnly);
499
500 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
501 ASSERT_TRUE(
502 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
503
504 auto transceivers = caller->pc()->GetTransceivers();
505 ASSERT_EQ(1u, transceivers.size());
506 // Since the remote transceiver was set to sendonly, the negotiated direction
507 // in the answer would be sendonly which we apply as recvonly to the local
508 // transceiver.
509 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
510 transceivers[0]->current_direction());
511}
512
513// Tests for multiple round trips.
514
515// Test that setting a transceiver with the inactive direction does not stop it
516// on either the caller or the callee.
517TEST_F(PeerConnectionJsepTest, SettingTransceiverInactiveDoesNotStopIt) {
518 auto caller = CreatePeerConnection();
519 caller->AddAudioTrack("a");
520 auto callee = CreatePeerConnection();
521 callee->AddAudioTrack("a");
522 callee->pc()->GetTransceivers()[0]->SetDirection(
523 RtpTransceiverDirection::kInactive);
524
525 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
526 ASSERT_TRUE(
527 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
528
529 EXPECT_FALSE(caller->pc()->GetTransceivers()[0]->stopped());
530 EXPECT_FALSE(callee->pc()->GetTransceivers()[0]->stopped());
531}
532
533// Test that if a transceiver had been associated and later stopped, then a
534// media section is still generated for it and the media section is marked as
535// rejected.
536TEST_F(PeerConnectionJsepTest,
537 ReOfferMediaSectionForAssociatedStoppedTransceiverIsRejected) {
538 auto caller = CreatePeerConnection();
539 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
540 auto callee = CreatePeerConnection();
541
542 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
543 ASSERT_TRUE(
544 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
545
546 ASSERT_TRUE(transceiver->mid());
547 transceiver->Stop();
548
549 auto reoffer = caller->CreateOffer();
550 auto contents = reoffer->description()->contents();
551 ASSERT_EQ(1u, contents.size());
552 EXPECT_TRUE(contents[0].rejected);
553}
554
555// Test that stopping an associated transceiver on the caller side will stop the
556// corresponding transceiver on the remote side when the remote offer is
557// applied.
558TEST_F(PeerConnectionJsepTest,
559 StoppingTransceiverInOfferStopsTransceiverOnRemoteSide) {
560 auto caller = CreatePeerConnection();
561 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
562 auto callee = CreatePeerConnection();
563
564 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
565 ASSERT_TRUE(
566 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
567
568 transceiver->Stop();
569
570 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
571
572 auto transceivers = callee->pc()->GetTransceivers();
573 EXPECT_TRUE(transceivers[0]->stopped());
574 EXPECT_TRUE(transceivers[0]->mid());
575}
576
577// Test that CreateOffer will only generate a recycled media section if the
578// transceiver to be recycled has been seen stopped by the other side first.
579TEST_F(PeerConnectionJsepTest,
580 CreateOfferDoesNotRecycleMediaSectionIfFirstStopped) {
581 auto caller = CreatePeerConnection();
582 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
583 auto callee = CreatePeerConnection();
584
585 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
586 ASSERT_TRUE(
587 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
588
589 auto second_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
590 first_transceiver->Stop();
591
592 auto reoffer = caller->CreateOffer();
593 auto contents = reoffer->description()->contents();
594 ASSERT_EQ(2u, contents.size());
595 EXPECT_TRUE(contents[0].rejected);
596 EXPECT_FALSE(contents[1].rejected);
597}
598
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800599// Test that the offer/answer and the transceivers are correctly generated and
600// updated when the media section is recycled after the callee stops a
601// transceiver and sends an answer with a 0 port.
602TEST_F(PeerConnectionJsepTest,
603 RecycleMediaSectionWhenStoppingTransceiverOnAnswerer) {
604 auto caller = CreatePeerConnection();
605 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
606 auto callee = CreatePeerConnection();
607
608 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
609 callee->pc()->GetTransceivers()[0]->Stop();
610 ASSERT_TRUE(
611 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
612 EXPECT_TRUE(first_transceiver->stopped());
613 // First transceivers aren't dissociated yet.
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200614 ASSERT_NE(absl::nullopt, first_transceiver->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800615 std::string first_mid = *first_transceiver->mid();
616 EXPECT_EQ(first_mid, callee->pc()->GetTransceivers()[0]->mid());
617
618 // New offer exchange with new transceivers that recycles the m section
619 // correctly.
620 caller->AddAudioTrack("audio2");
621 callee->AddAudioTrack("audio2");
622 auto offer = caller->CreateOffer();
623 auto offer_contents = offer->description()->contents();
624 std::string second_mid = offer_contents[0].name;
625 ASSERT_EQ(1u, offer_contents.size());
626 EXPECT_FALSE(offer_contents[0].rejected);
627 EXPECT_NE(first_mid, second_mid);
628
629 // Setting the offer on each side will dissociate the first transceivers and
630 // associate the new transceivers.
631 ASSERT_TRUE(
632 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200633 EXPECT_EQ(absl::nullopt, first_transceiver->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800634 EXPECT_EQ(second_mid, caller->pc()->GetTransceivers()[1]->mid());
635 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200636 EXPECT_EQ(absl::nullopt, callee->pc()->GetTransceivers()[0]->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800637 EXPECT_EQ(second_mid, callee->pc()->GetTransceivers()[1]->mid());
638
639 // The new answer should also recycle the m section correctly.
640 auto answer = callee->CreateAnswer();
641 auto answer_contents = answer->description()->contents();
642 ASSERT_EQ(1u, answer_contents.size());
643 EXPECT_FALSE(answer_contents[0].rejected);
644 EXPECT_EQ(second_mid, answer_contents[0].name);
645
646 // Finishing the negotiation shouldn't add or dissociate any transceivers.
647 ASSERT_TRUE(
648 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
649 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
650 auto caller_transceivers = caller->pc()->GetTransceivers();
651 ASSERT_EQ(2u, caller_transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200652 EXPECT_EQ(absl::nullopt, caller_transceivers[0]->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800653 EXPECT_EQ(second_mid, caller_transceivers[1]->mid());
654 auto callee_transceivers = callee->pc()->GetTransceivers();
655 ASSERT_EQ(2u, callee_transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200656 EXPECT_EQ(absl::nullopt, callee_transceivers[0]->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800657 EXPECT_EQ(second_mid, callee_transceivers[1]->mid());
658}
659
660// Test that creating/setting a local offer that recycles an m= section is
661// idempotent.
662TEST_F(PeerConnectionJsepTest, CreateOfferRecyclesWhenOfferingTwice) {
663 // Do a negotiation with a port 0 for the media section.
664 auto caller = CreatePeerConnection();
665 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
666 auto callee = CreatePeerConnection();
667 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
668 first_transceiver->Stop();
669 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
670 caller->AddAudioTrack("audio2");
671
672 // Create a new offer that recycles the media section and set it as a local
673 // description.
674 auto offer = caller->CreateOffer();
675 auto offer_contents = offer->description()->contents();
676 ASSERT_EQ(1u, offer_contents.size());
677 EXPECT_FALSE(offer_contents[0].rejected);
678 ASSERT_TRUE(caller->SetLocalDescription(std::move(offer)));
679 EXPECT_FALSE(caller->pc()->GetTransceivers()[1]->stopped());
680 std::string second_mid = offer_contents[0].name;
681
682 // Create another new offer and set the local description again without the
683 // rest of any negotation ocurring.
684 auto second_offer = caller->CreateOffer();
685 auto second_offer_contents = second_offer->description()->contents();
686 ASSERT_EQ(1u, second_offer_contents.size());
687 EXPECT_FALSE(second_offer_contents[0].rejected);
688 // The mid shouldn't change.
689 EXPECT_EQ(second_mid, second_offer_contents[0].name);
690
691 ASSERT_TRUE(caller->SetLocalDescription(std::move(second_offer)));
692 // Make sure that the caller's transceivers are associated correctly.
693 auto caller_transceivers = caller->pc()->GetTransceivers();
694 ASSERT_EQ(2u, caller_transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200695 EXPECT_EQ(absl::nullopt, caller_transceivers[0]->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800696 EXPECT_EQ(second_mid, caller_transceivers[1]->mid());
697 EXPECT_FALSE(caller_transceivers[1]->stopped());
698}
699
Steve Antondcc3c022017-12-22 16:02:54 -0800700// Test that the offer/answer and transceivers for both the caller and callee
701// side are generated/updated correctly when recycling an audio/video media
702// section as a media section of either the same or opposite type.
703class RecycleMediaSectionTest
704 : public PeerConnectionJsepTest,
705 public testing::WithParamInterface<
706 std::tuple<cricket::MediaType, cricket::MediaType>> {
707 protected:
708 RecycleMediaSectionTest() {
709 first_type_ = std::get<0>(GetParam());
710 second_type_ = std::get<1>(GetParam());
711 }
712
713 cricket::MediaType first_type_;
714 cricket::MediaType second_type_;
715};
716
717TEST_P(RecycleMediaSectionTest, VerifyOfferAnswerAndTransceivers) {
718 auto caller = CreatePeerConnection();
719 auto first_transceiver = caller->AddTransceiver(first_type_);
720 auto callee = CreatePeerConnection();
721
722 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
723
724 std::string first_mid = *first_transceiver->mid();
725 first_transceiver->Stop();
726
727 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
728
729 auto second_transceiver = caller->AddTransceiver(second_type_);
730
731 // The offer should reuse the previous media section but allocate a new MID
732 // and change the media type.
733 auto offer = caller->CreateOffer();
734 auto offer_contents = offer->description()->contents();
735 ASSERT_EQ(1u, offer_contents.size());
736 EXPECT_FALSE(offer_contents[0].rejected);
737 EXPECT_EQ(second_type_, offer_contents[0].media_description()->type());
738 std::string second_mid = offer_contents[0].name;
739 EXPECT_NE(first_mid, second_mid);
740
741 // Setting the local offer will dissociate the previous transceiver and set
742 // the MID for the new transceiver.
743 ASSERT_TRUE(
744 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200745 EXPECT_EQ(absl::nullopt, first_transceiver->mid());
Steve Antondcc3c022017-12-22 16:02:54 -0800746 EXPECT_EQ(second_mid, second_transceiver->mid());
747
748 // Setting the remote offer will dissociate the previous transceiver and
749 // create a new transceiver for the media section.
750 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
751 auto callee_transceivers = callee->pc()->GetTransceivers();
752 ASSERT_EQ(2u, callee_transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200753 EXPECT_EQ(absl::nullopt, callee_transceivers[0]->mid());
Steve Anton69470252018-02-09 11:43:08 -0800754 EXPECT_EQ(first_type_, callee_transceivers[0]->media_type());
Steve Antondcc3c022017-12-22 16:02:54 -0800755 EXPECT_EQ(second_mid, callee_transceivers[1]->mid());
Steve Anton69470252018-02-09 11:43:08 -0800756 EXPECT_EQ(second_type_, callee_transceivers[1]->media_type());
Steve Antondcc3c022017-12-22 16:02:54 -0800757
758 // The answer should have only one media section for the new transceiver.
759 auto answer = callee->CreateAnswer();
760 auto answer_contents = answer->description()->contents();
761 ASSERT_EQ(1u, answer_contents.size());
762 EXPECT_FALSE(answer_contents[0].rejected);
763 EXPECT_EQ(second_mid, answer_contents[0].name);
764 EXPECT_EQ(second_type_, answer_contents[0].media_description()->type());
765
766 // Setting the local answer should succeed.
767 ASSERT_TRUE(
768 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
769
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800770 // Setting the remote answer should succeed and not create any new
771 // transceivers.
Steve Antondcc3c022017-12-22 16:02:54 -0800772 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800773 ASSERT_EQ(2u, caller->pc()->GetTransceivers().size());
774 ASSERT_EQ(2u, callee->pc()->GetTransceivers().size());
Steve Antondcc3c022017-12-22 16:02:54 -0800775}
776
777// Test all combinations of audio and video as the first and second media type
778// for the media section. This is needed for full test coverage because
779// MediaSession has separate functions for processing audio and video media
780// sections.
781INSTANTIATE_TEST_CASE_P(
782 PeerConnectionJsepTest,
783 RecycleMediaSectionTest,
784 Combine(Values(cricket::MEDIA_TYPE_AUDIO, cricket::MEDIA_TYPE_VIDEO),
785 Values(cricket::MEDIA_TYPE_AUDIO, cricket::MEDIA_TYPE_VIDEO)));
786
Steve Antonfa2260d2017-12-28 16:38:23 -0800787// Test that a new data channel section will not reuse a recycleable audio or
788// video media section. Additionally, tests that the new section is added to the
789// end of the session description.
790TEST_F(PeerConnectionJsepTest, DataChannelDoesNotRecycleMediaSection) {
791 auto caller = CreatePeerConnection();
792 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
793 auto callee = CreatePeerConnection();
794
795 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
796
797 transceiver->Stop();
798
799 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
800
801 caller->CreateDataChannel("dc");
802
803 auto offer = caller->CreateOffer();
804 auto offer_contents = offer->description()->contents();
805 ASSERT_EQ(2u, offer_contents.size());
806 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO,
807 offer_contents[0].media_description()->type());
808 EXPECT_EQ(cricket::MEDIA_TYPE_DATA,
809 offer_contents[1].media_description()->type());
810
811 ASSERT_TRUE(
812 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
813 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
814
815 auto answer = callee->CreateAnswer();
816 auto answer_contents = answer->description()->contents();
817 ASSERT_EQ(2u, answer_contents.size());
818 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO,
819 answer_contents[0].media_description()->type());
820 EXPECT_EQ(cricket::MEDIA_TYPE_DATA,
821 answer_contents[1].media_description()->type());
822}
823
824// Test that if a new track is added to an existing session that has a data,
825// the new section comes at the end of the new offer, after the existing data
826// section.
827TEST_F(PeerConnectionJsepTest, AudioTrackAddedAfterDataSectionInReoffer) {
828 auto caller = CreatePeerConnection();
829 caller->CreateDataChannel("dc");
830 auto callee = CreatePeerConnection();
831
832 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
833
834 caller->AddAudioTrack("a");
835
836 auto offer = caller->CreateOffer();
837 auto contents = offer->description()->contents();
838 ASSERT_EQ(2u, contents.size());
839 EXPECT_EQ(cricket::MEDIA_TYPE_DATA, contents[0].media_description()->type());
840 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, contents[1].media_description()->type());
841}
842
Steve Antondcc3c022017-12-22 16:02:54 -0800843// Tests for MID properties.
844
845static void RenameSection(size_t mline_index,
846 const std::string& new_mid,
847 SessionDescriptionInterface* sdesc) {
848 cricket::SessionDescription* desc = sdesc->description();
849 std::string old_mid = desc->contents()[mline_index].name;
850 desc->contents()[mline_index].name = new_mid;
851 desc->transport_infos()[mline_index].content_name = new_mid;
852 const cricket::ContentGroup* bundle =
853 desc->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
854 if (bundle) {
855 cricket::ContentGroup new_bundle = *bundle;
856 if (new_bundle.RemoveContentName(old_mid)) {
857 new_bundle.AddContentName(new_mid);
858 }
859 desc->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
860 desc->AddGroup(new_bundle);
861 }
862}
863
864// Test that two PeerConnections can have a successful offer/answer exchange if
865// the MIDs are changed from the defaults.
866TEST_F(PeerConnectionJsepTest, OfferAnswerWithChangedMids) {
867 constexpr char kFirstMid[] = "nondefaultmid";
868 constexpr char kSecondMid[] = "randommid";
869
870 auto caller = CreatePeerConnection();
871 caller->AddAudioTrack("a");
872 caller->AddAudioTrack("b");
873 auto callee = CreatePeerConnection();
874
875 auto offer = caller->CreateOffer();
876 RenameSection(0, kFirstMid, offer.get());
877 RenameSection(1, kSecondMid, offer.get());
878
879 ASSERT_TRUE(
880 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
881 auto caller_transceivers = caller->pc()->GetTransceivers();
882 EXPECT_EQ(kFirstMid, caller_transceivers[0]->mid());
883 EXPECT_EQ(kSecondMid, caller_transceivers[1]->mid());
884
885 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
886 auto callee_transceivers = callee->pc()->GetTransceivers();
887 EXPECT_EQ(kFirstMid, callee_transceivers[0]->mid());
888 EXPECT_EQ(kSecondMid, callee_transceivers[1]->mid());
889
890 auto answer = callee->CreateAnswer();
891 auto answer_contents = answer->description()->contents();
892 EXPECT_EQ(kFirstMid, answer_contents[0].name);
893 EXPECT_EQ(kSecondMid, answer_contents[1].name);
894
895 ASSERT_TRUE(
896 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
897 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
898}
899
900// Test that CreateOffer will generate a MID that is not already used if the
901// default it would have picked is already taken. This is tested by using a
902// third PeerConnection to determine what the default would be for the second
903// media section then setting that as the first media section's MID.
904TEST_F(PeerConnectionJsepTest, CreateOfferGeneratesUniqueMidIfAlreadyTaken) {
905 // First, find what the default MID is for the second media section.
906 auto pc = CreatePeerConnection();
907 pc->AddAudioTrack("a");
908 pc->AddAudioTrack("b");
909 auto default_offer = pc->CreateOffer();
910 std::string default_second_mid =
911 default_offer->description()->contents()[1].name;
912
913 // Now, do an offer/answer with one track which has the MID set to the default
914 // second MID.
915 auto caller = CreatePeerConnection();
916 caller->AddAudioTrack("a");
917 auto callee = CreatePeerConnection();
918
919 auto offer = caller->CreateOffer();
920 RenameSection(0, default_second_mid, offer.get());
921
922 ASSERT_TRUE(
923 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
924 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
925 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
926
927 // Add a second track and ensure that the MID is different.
928 caller->AddAudioTrack("b");
929
930 auto reoffer = caller->CreateOffer();
931 auto reoffer_contents = reoffer->description()->contents();
932 EXPECT_EQ(default_second_mid, reoffer_contents[0].name);
933 EXPECT_NE(reoffer_contents[0].name, reoffer_contents[1].name);
934}
935
Steve Antonfa2260d2017-12-28 16:38:23 -0800936// Test that if an audio or video section has the default data section MID, then
937// CreateOffer will generate a unique MID for the newly added data section.
938TEST_F(PeerConnectionJsepTest,
939 CreateOfferGeneratesUniqueMidForDataSectionIfAlreadyTaken) {
940 // First, find what the default MID is for the data channel.
941 auto pc = CreatePeerConnection();
942 pc->CreateDataChannel("dc");
943 auto default_offer = pc->CreateOffer();
944 std::string default_data_mid =
945 default_offer->description()->contents()[0].name;
946
947 // Now do an offer/answer with one audio track which has a MID set to the
948 // default data MID.
949 auto caller = CreatePeerConnection();
950 caller->AddAudioTrack("a");
951 auto callee = CreatePeerConnection();
952
953 auto offer = caller->CreateOffer();
954 RenameSection(0, default_data_mid, offer.get());
955
956 ASSERT_TRUE(
957 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
958 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
959 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
960
961 // Add a data channel and ensure that the MID is different.
962 caller->CreateDataChannel("dc");
963
964 auto reoffer = caller->CreateOffer();
965 auto reoffer_contents = reoffer->description()->contents();
966 EXPECT_EQ(default_data_mid, reoffer_contents[0].name);
967 EXPECT_NE(reoffer_contents[0].name, reoffer_contents[1].name);
968}
969
Steve Antondcc3c022017-12-22 16:02:54 -0800970// Test that a reoffer initiated by the callee adds a new track to the caller.
971TEST_F(PeerConnectionJsepTest, CalleeDoesReoffer) {
972 auto caller = CreatePeerConnection();
973 caller->AddAudioTrack("a");
974 auto callee = CreatePeerConnection();
975 callee->AddAudioTrack("a");
976 callee->AddVideoTrack("v");
977
978 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
979
980 EXPECT_EQ(1u, caller->pc()->GetTransceivers().size());
981 EXPECT_EQ(2u, callee->pc()->GetTransceivers().size());
982
983 ASSERT_TRUE(callee->ExchangeOfferAnswerWith(caller.get()));
984
985 EXPECT_EQ(2u, caller->pc()->GetTransceivers().size());
986 EXPECT_EQ(2u, callee->pc()->GetTransceivers().size());
987}
988
Steve Anton02ee47c2018-01-10 16:26:06 -0800989// Tests for MSID properties.
990
991// Test that adding a track with AddTrack results in an offer that signals the
992// track's ID.
993TEST_F(PeerConnectionJsepTest, AddingTrackWithAddTrackSpecifiesTrackId) {
994 const std::string kTrackId = "audio_track";
995
996 auto caller = CreatePeerConnection();
997 caller->AddAudioTrack(kTrackId);
998
999 auto offer = caller->CreateOffer();
1000 auto contents = offer->description()->contents();
1001 ASSERT_EQ(1u, contents.size());
1002 auto streams = contents[0].media_description()->streams();
1003 ASSERT_EQ(1u, streams.size());
1004 EXPECT_EQ(kTrackId, streams[0].id);
1005}
1006
1007// Test that adding a track by calling AddTransceiver then SetTrack results in
1008// an offer that does not signal the track's ID and signals a random ID.
1009TEST_F(PeerConnectionJsepTest,
1010 AddingTrackWithAddTransceiverSpecifiesRandomTrackId) {
1011 const std::string kTrackId = "audio_track";
1012
1013 auto caller = CreatePeerConnection();
1014 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1015 transceiver->sender()->SetTrack(caller->CreateAudioTrack(kTrackId));
1016
1017 auto offer = caller->CreateOffer();
1018 auto contents = offer->description()->contents();
1019 ASSERT_EQ(1u, contents.size());
1020 auto streams = contents[0].media_description()->streams();
1021 ASSERT_EQ(1u, streams.size());
1022 EXPECT_NE(kTrackId, streams[0].id);
1023}
1024
Steve Anton5f94aa22018-02-01 10:58:30 -08001025// Test that if the transceiver is recvonly or inactive, then no MSID
1026// information is included in the offer.
1027TEST_F(PeerConnectionJsepTest, NoMsidInOfferIfTransceiverDirectionHasNoSend) {
1028 auto caller = CreatePeerConnection();
1029
1030 RtpTransceiverInit init_recvonly;
1031 init_recvonly.direction = RtpTransceiverDirection::kRecvOnly;
1032 ASSERT_TRUE(caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init_recvonly));
1033
1034 RtpTransceiverInit init_inactive;
1035 init_inactive.direction = RtpTransceiverDirection::kInactive;
1036 ASSERT_TRUE(caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init_inactive));
1037
1038 auto offer = caller->CreateOffer();
1039 auto contents = offer->description()->contents();
1040 ASSERT_EQ(2u, contents.size());
1041 // MSID is specified in the first stream, so no streams means no MSID.
1042 EXPECT_EQ(0u, contents[0].media_description()->streams().size());
1043 EXPECT_EQ(0u, contents[1].media_description()->streams().size());
1044}
1045
1046// Test that if an answer negotiates transceiver directions of recvonly or
1047// inactive, then no MSID information is included in the answer.
1048TEST_F(PeerConnectionJsepTest, NoMsidInAnswerIfNoRespondingTracks) {
1049 auto caller = CreatePeerConnection();
1050 auto callee = CreatePeerConnection();
1051
1052 // recvonly transceiver will get negotiated to inactive since the callee has
1053 // no tracks to send in response.
1054 RtpTransceiverInit init_recvonly;
1055 init_recvonly.direction = RtpTransceiverDirection::kRecvOnly;
1056 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init_recvonly);
1057
1058 // sendrecv transceiver will get negotiated to recvonly since the callee has
1059 // no tracks to send in response.
1060 RtpTransceiverInit init_sendrecv;
1061 init_sendrecv.direction = RtpTransceiverDirection::kSendRecv;
1062 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init_sendrecv);
1063
1064 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1065
1066 auto answer = callee->CreateAnswer();
1067 auto contents = answer->description()->contents();
1068 ASSERT_EQ(2u, contents.size());
1069 // MSID is specified in the first stream, so no streams means no MSID.
1070 EXPECT_EQ(0u, contents[0].media_description()->streams().size());
1071 EXPECT_EQ(0u, contents[1].media_description()->streams().size());
1072}
1073
1074// Test that the MSID is included even if the transceiver direction has changed
1075// to inactive if the transceiver had previously sent media.
1076TEST_F(PeerConnectionJsepTest, IncludeMsidEvenIfDirectionHasChanged) {
1077 auto caller = CreatePeerConnection();
1078 caller->AddAudioTrack("audio");
1079 auto callee = CreatePeerConnection();
1080 callee->AddAudioTrack("audio");
1081
1082 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1083
1084 caller->pc()->GetTransceivers()[0]->SetDirection(
1085 RtpTransceiverDirection::kInactive);
1086
1087 // The transceiver direction on both sides will turn to inactive.
1088 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1089
1090 auto* offer = callee->pc()->remote_description();
1091 auto offer_contents = offer->description()->contents();
1092 ASSERT_EQ(1u, offer_contents.size());
1093 // MSID is specified in the first stream. If it is present, assume that MSID
1094 // is there.
1095 EXPECT_EQ(1u, offer_contents[0].media_description()->streams().size());
1096
1097 auto* answer = caller->pc()->remote_description();
1098 auto answer_contents = answer->description()->contents();
1099 ASSERT_EQ(1u, answer_contents.size());
1100 EXPECT_EQ(1u, answer_contents[0].media_description()->streams().size());
1101}
1102
1103// Test that stopping a RtpTransceiver will cause future offers to not include
1104// any MSID information for that section.
1105TEST_F(PeerConnectionJsepTest, RemoveMsidIfTransceiverStopped) {
1106 auto caller = CreatePeerConnection();
1107 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1108 auto callee = CreatePeerConnection();
1109
1110 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1111
1112 transceiver->Stop();
1113
1114 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1115
1116 auto* offer = callee->pc()->remote_description();
1117 auto offer_contents = offer->description()->contents();
1118 ASSERT_EQ(1u, offer_contents.size());
1119 // MSID is specified in the first stream, so no streams means no MSID.
1120 EXPECT_EQ(0u, offer_contents[0].media_description()->streams().size());
1121}
1122
Steve Anton02ee47c2018-01-10 16:26:06 -08001123// Test that the callee RtpReceiver created by a call to SetRemoteDescription
1124// has its ID set to the signaled track ID.
1125TEST_F(PeerConnectionJsepTest,
1126 RtpReceiverCreatedBySetRemoteDescriptionHasSignaledTrackId) {
1127 const std::string kTrackId = "audio_track";
1128
1129 auto caller = CreatePeerConnection();
1130 auto callee = CreatePeerConnection();
1131 caller->AddAudioTrack(kTrackId);
1132
1133 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1134
1135 ASSERT_EQ(1u, callee->pc()->GetReceivers().size());
1136 auto receiver = callee->pc()->GetReceivers()[0];
1137 EXPECT_EQ(kTrackId, receiver->id());
1138}
1139
1140// Test that if the callee RtpReceiver is reused by a call to
1141// SetRemoteDescription, its ID does not change.
1142TEST_F(PeerConnectionJsepTest,
1143 RtpReceiverCreatedBeforeSetRemoteDescriptionKeepsId) {
1144 const std::string kTrackId = "audio_track";
1145
1146 auto caller = CreatePeerConnection();
1147 auto callee = CreatePeerConnection();
1148 caller->AddAudioTrack(kTrackId);
1149 callee->AddAudioTrack("dummy_track");
1150
1151 ASSERT_EQ(1u, callee->pc()->GetReceivers().size());
1152 auto receiver = callee->pc()->GetReceivers()[0];
1153 std::string receiver_id = receiver->id();
1154
1155 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1156
1157 EXPECT_EQ(receiver_id, receiver->id());
1158}
1159
Steve Antonef65ef12018-01-10 17:15:20 -08001160// Test that setting a remote offer with one track that has no streams fires off
1161// the correct OnAddTrack event.
1162TEST_F(PeerConnectionJsepTest,
1163 SetRemoteOfferWithOneTrackNoStreamFiresOnAddTrack) {
1164 const std::string kTrackLabel = "audio_track";
1165
1166 auto caller = CreatePeerConnection();
1167 auto callee = CreatePeerConnection();
1168 ASSERT_TRUE(caller->AddAudioTrack(kTrackLabel));
1169
1170 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1171
Seth Hampson5b4f0752018-04-02 16:31:36 -07001172 const auto& track_events = callee->observer()->add_track_events_;
1173 ASSERT_EQ(1u, track_events.size());
1174 const auto& event = track_events[0];
1175 EXPECT_EQ(kTrackLabel, event.receiver->track()->id());
1176 EXPECT_EQ(0u, event.streams.size());
Steve Antonef65ef12018-01-10 17:15:20 -08001177}
1178
1179// Test that setting a remote offer with one track that has one stream fires off
1180// the correct OnAddTrack event.
1181TEST_F(PeerConnectionJsepTest,
1182 SetRemoteOfferWithOneTrackOneStreamFiresOnAddTrack) {
1183 const std::string kTrackLabel = "audio_track";
Seth Hampson845e8782018-03-02 11:34:10 -08001184 const std::string kStreamId = "audio_stream";
Steve Antonef65ef12018-01-10 17:15:20 -08001185
1186 auto caller = CreatePeerConnection();
1187 auto callee = CreatePeerConnection();
Seth Hampson845e8782018-03-02 11:34:10 -08001188 ASSERT_TRUE(caller->AddAudioTrack(kTrackLabel, {kStreamId}));
Steve Antonef65ef12018-01-10 17:15:20 -08001189
1190 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1191
1192 const auto& track_events = callee->observer()->add_track_events_;
1193 ASSERT_EQ(1u, track_events.size());
1194 const auto& event = track_events[0];
1195 ASSERT_EQ(1u, event.streams.size());
1196 auto stream = event.streams[0];
Seth Hampson13b8bad2018-03-13 16:05:28 -07001197 EXPECT_EQ(kStreamId, stream->id());
Steve Antonef65ef12018-01-10 17:15:20 -08001198 EXPECT_THAT(track_events[0].snapshotted_stream_tracks.at(stream),
1199 ElementsAre(event.receiver->track()));
1200 EXPECT_EQ(event.receiver->streams(), track_events[0].streams);
1201}
1202
1203// Test that setting a remote offer with two tracks that share the same stream
1204// fires off two OnAddTrack events, both with the same stream that has both
1205// tracks present at the time of firing. This is to ensure that track events are
1206// not fired until SetRemoteDescription has finished processing all the media
1207// sections.
1208TEST_F(PeerConnectionJsepTest,
1209 SetRemoteOfferWithTwoTracksSameStreamFiresOnAddTrack) {
1210 const std::string kTrack1Label = "audio_track1";
1211 const std::string kTrack2Label = "audio_track2";
Seth Hampson845e8782018-03-02 11:34:10 -08001212 const std::string kSharedStreamId = "stream";
Steve Antonef65ef12018-01-10 17:15:20 -08001213
1214 auto caller = CreatePeerConnection();
1215 auto callee = CreatePeerConnection();
Seth Hampson845e8782018-03-02 11:34:10 -08001216 ASSERT_TRUE(caller->AddAudioTrack(kTrack1Label, {kSharedStreamId}));
1217 ASSERT_TRUE(caller->AddAudioTrack(kTrack2Label, {kSharedStreamId}));
Steve Antonef65ef12018-01-10 17:15:20 -08001218
1219 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1220
1221 const auto& track_events = callee->observer()->add_track_events_;
1222 ASSERT_EQ(2u, track_events.size());
1223 const auto& event1 = track_events[0];
1224 const auto& event2 = track_events[1];
1225 ASSERT_EQ(1u, event1.streams.size());
1226 auto stream = event1.streams[0];
1227 ASSERT_THAT(event2.streams, ElementsAre(stream));
1228 auto track1 = event1.receiver->track();
1229 auto track2 = event2.receiver->track();
1230 EXPECT_THAT(event1.snapshotted_stream_tracks.at(stream),
1231 UnorderedElementsAre(track1, track2));
1232 EXPECT_THAT(event2.snapshotted_stream_tracks.at(stream),
1233 UnorderedElementsAre(track1, track2));
1234}
1235
Seth Hampson5b4f0752018-04-02 16:31:36 -07001236// Test that setting a remote offer with one track that has two streams fires
1237// off the correct OnAddTrack event.
1238TEST_F(PeerConnectionJsepTest,
1239 SetRemoteOfferWithOneTrackTwoStreamFiresOnAddTrack) {
1240 const std::string kTrackLabel = "audio_track";
1241 const std::string kStreamId1 = "audio_stream1";
1242 const std::string kStreamId2 = "audio_stream2";
1243
1244 auto caller = CreatePeerConnection();
1245 auto callee = CreatePeerConnection();
1246 ASSERT_TRUE(caller->AddAudioTrack(kTrackLabel, {kStreamId1, kStreamId2}));
1247
1248 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1249
1250 const auto& track_events = callee->observer()->add_track_events_;
1251 ASSERT_EQ(1u, track_events.size());
1252 const auto& event = track_events[0];
1253 ASSERT_EQ(2u, event.streams.size());
1254 EXPECT_EQ(kStreamId1, event.streams[0]->id());
1255 EXPECT_EQ(kStreamId2, event.streams[1]->id());
1256}
Steve Antonef65ef12018-01-10 17:15:20 -08001257
Steve Anton54b84072018-02-20 15:19:52 -08001258// Test that if an RtpTransceiver with a current_direction set is stopped, then
1259// current_direction is changed to null.
1260TEST_F(PeerConnectionJsepTest, CurrentDirectionResetWhenRtpTransceiverStopped) {
1261 auto caller = CreatePeerConnection();
1262 auto callee = CreatePeerConnection();
1263
1264 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1265
1266 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1267
1268 ASSERT_TRUE(transceiver->current_direction());
1269 transceiver->Stop();
1270 EXPECT_FALSE(transceiver->current_direction());
1271}
1272
Steve Antonba42e992018-04-09 14:10:01 -07001273// Test that you can't set an answer on a PeerConnection before setting the
1274// offer.
Harald Alvestrand5081c0c2018-03-09 15:18:03 +01001275TEST_F(PeerConnectionJsepTest, AnswerBeforeOfferFails) {
1276 auto caller = CreatePeerConnection();
1277 auto callee = CreatePeerConnection();
Harald Alvestrand5081c0c2018-03-09 15:18:03 +01001278 caller->AddAudioTrack("audio");
Steve Antonba42e992018-04-09 14:10:01 -07001279
1280 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1281
1282 RTCError error;
1283 ASSERT_FALSE(caller->SetRemoteDescription(callee->CreateAnswer(), &error));
1284 EXPECT_EQ(RTCErrorType::INVALID_STATE, error.type());
1285}
1286
1287// Test that a Unified Plan PeerConnection fails to set a Plan B offer if it has
1288// two video tracks.
1289TEST_F(PeerConnectionJsepTest, TwoVideoPlanBToUnifiedPlanFails) {
1290 RTCConfiguration config_planb;
1291 config_planb.sdp_semantics = SdpSemantics::kPlanB;
1292 auto caller = CreatePeerConnection(config_planb);
1293 auto callee = CreatePeerConnection();
1294 caller->AddVideoTrack("video1");
1295 caller->AddVideoTrack("video2");
1296
1297 RTCError error;
1298 ASSERT_FALSE(callee->SetRemoteDescription(caller->CreateOffer(), &error));
1299 EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, error.type());
1300}
1301
1302// Test that a Unified Plan PeerConnection fails to set a Plan B answer if it
1303// has two video tracks.
1304TEST_F(PeerConnectionJsepTest, OneVideoUnifiedPlanToTwoVideoPlanBFails) {
1305 auto caller = CreatePeerConnection();
1306 RTCConfiguration config_planb;
1307 config_planb.sdp_semantics = SdpSemantics::kPlanB;
1308 auto callee = CreatePeerConnection(config_planb);
1309 caller->AddVideoTrack("video");
1310 callee->AddVideoTrack("video1");
1311 callee->AddVideoTrack("video2");
1312
1313 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1314
1315 RTCError error;
1316 ASSERT_FALSE(caller->SetRemoteDescription(caller->CreateAnswer(), &error));
1317 EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, error.type());
Harald Alvestrand5081c0c2018-03-09 15:18:03 +01001318}
1319
Steve Antondcc3c022017-12-22 16:02:54 -08001320} // namespace webrtc