blob: 737b0c96f72796de1beff8fc7b2b155a59b8e451 [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"
Steve Antonfa2260d2017-12-28 16:38:23 -080013#include "media/engine/webrtcmediaengine.h"
14#include "modules/audio_processing/include/audio_processing.h"
Steve Antondcc3c022017-12-22 16:02:54 -080015#include "pc/mediasession.h"
Steve Antonfa2260d2017-12-28 16:38:23 -080016#include "pc/peerconnectionfactory.h"
Steve Antondcc3c022017-12-22 16:02:54 -080017#include "pc/peerconnectionwrapper.h"
18#include "pc/sdputils.h"
19#ifdef WEBRTC_ANDROID
20#include "pc/test/androidtestinitializer.h"
21#endif
22#include "pc/test/fakeaudiocapturemodule.h"
Steve Antonfa2260d2017-12-28 16:38:23 -080023#include "pc/test/fakesctptransport.h"
Steve Antondcc3c022017-12-22 16:02:54 -080024#include "rtc_base/gunit.h"
25#include "rtc_base/ptr_util.h"
26#include "rtc_base/virtualsocketserver.h"
27#include "test/gmock.h"
28
29// This file contains tests that ensure the PeerConnection's implementation of
30// CreateOffer/CreateAnswer/SetLocalDescription/SetRemoteDescription conform
31// to the JavaScript Session Establishment Protocol (JSEP).
32// For now these semantics are only available when configuring the
33// PeerConnection with Unified Plan, but eventually that will be the default.
34
35namespace webrtc {
36
37using cricket::MediaContentDescription;
38using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
39using ::testing::Values;
40using ::testing::Combine;
41using ::testing::ElementsAre;
Steve Antonef65ef12018-01-10 17:15:20 -080042using ::testing::UnorderedElementsAre;
Steve Antondcc3c022017-12-22 16:02:54 -080043
Steve Antonfa2260d2017-12-28 16:38:23 -080044class PeerConnectionFactoryForJsepTest : public PeerConnectionFactory {
45 public:
46 PeerConnectionFactoryForJsepTest()
47 : PeerConnectionFactory(
48 rtc::Thread::Current(),
49 rtc::Thread::Current(),
50 rtc::Thread::Current(),
51 rtc::WrapUnique(cricket::WebRtcMediaEngineFactory::Create(
52 FakeAudioCaptureModule::Create(),
53 CreateBuiltinAudioEncoderFactory(),
54 CreateBuiltinAudioDecoderFactory(),
55 nullptr,
56 nullptr,
57 nullptr,
Ivo Creusen62337e52018-01-09 14:17:33 +010058 AudioProcessingBuilder().Create())),
Steve Antonfa2260d2017-12-28 16:38:23 -080059 CreateCallFactory(),
60 nullptr) {}
61
62 std::unique_ptr<cricket::SctpTransportInternalFactory>
63 CreateSctpTransportInternalFactory() {
64 return rtc::MakeUnique<FakeSctpTransportFactory>();
65 }
66};
67
Steve Antondcc3c022017-12-22 16:02:54 -080068class PeerConnectionJsepTest : public ::testing::Test {
69 protected:
70 typedef std::unique_ptr<PeerConnectionWrapper> WrapperPtr;
71
72 PeerConnectionJsepTest()
73 : vss_(new rtc::VirtualSocketServer()), main_(vss_.get()) {
74#ifdef WEBRTC_ANDROID
75 InitializeAndroidObjects();
76#endif
Steve Antondcc3c022017-12-22 16:02:54 -080077 }
78
79 WrapperPtr CreatePeerConnection() {
80 RTCConfiguration config;
81 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
82 return CreatePeerConnection(config);
83 }
84
85 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
Steve Antonfa2260d2017-12-28 16:38:23 -080086 rtc::scoped_refptr<PeerConnectionFactory> pc_factory(
87 new rtc::RefCountedObject<PeerConnectionFactoryForJsepTest>());
88 RTC_CHECK(pc_factory->Initialize());
Steve Antondcc3c022017-12-22 16:02:54 -080089 auto observer = rtc::MakeUnique<MockPeerConnectionObserver>();
Steve Antonfa2260d2017-12-28 16:38:23 -080090 auto pc = pc_factory->CreatePeerConnection(config, nullptr, nullptr,
91 observer.get());
Steve Antondcc3c022017-12-22 16:02:54 -080092 if (!pc) {
93 return nullptr;
94 }
95
Steve Antonfa2260d2017-12-28 16:38:23 -080096 return rtc::MakeUnique<PeerConnectionWrapper>(pc_factory, pc,
Steve Antondcc3c022017-12-22 16:02:54 -080097 std::move(observer));
98 }
99
100 std::unique_ptr<rtc::VirtualSocketServer> vss_;
101 rtc::AutoSocketServerThread main_;
Steve Antondcc3c022017-12-22 16:02:54 -0800102};
103
104// Tests for JSEP initial offer generation.
105
106// Test that an offer created by a PeerConnection with no transceivers generates
107// no media sections.
108TEST_F(PeerConnectionJsepTest, EmptyInitialOffer) {
109 auto caller = CreatePeerConnection();
Steve Antonfa2260d2017-12-28 16:38:23 -0800110
Steve Antondcc3c022017-12-22 16:02:54 -0800111 auto offer = caller->CreateOffer();
Steve Antonfa2260d2017-12-28 16:38:23 -0800112 ASSERT_EQ(0u, offer->description()->contents().size());
Steve Antondcc3c022017-12-22 16:02:54 -0800113}
114
115// Test that an initial offer with one audio track generates one audio media
116// section.
117TEST_F(PeerConnectionJsepTest, AudioOnlyInitialOffer) {
118 auto caller = CreatePeerConnection();
119 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
Steve Antondcc3c022017-12-22 16:02:54 -0800120
Steve Antonfa2260d2017-12-28 16:38:23 -0800121 auto offer = caller->CreateOffer();
Steve Antondcc3c022017-12-22 16:02:54 -0800122 auto contents = offer->description()->contents();
123 ASSERT_EQ(1u, contents.size());
124 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, contents[0].media_description()->type());
125}
126
127// Test than an initial offer with one video track generates one video media
128// section
129TEST_F(PeerConnectionJsepTest, VideoOnlyInitialOffer) {
130 auto caller = CreatePeerConnection();
131 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
Steve Antondcc3c022017-12-22 16:02:54 -0800132
Steve Antonfa2260d2017-12-28 16:38:23 -0800133 auto offer = caller->CreateOffer();
Steve Antondcc3c022017-12-22 16:02:54 -0800134 auto contents = offer->description()->contents();
135 ASSERT_EQ(1u, contents.size());
136 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, contents[0].media_description()->type());
137}
138
Steve Antonfa2260d2017-12-28 16:38:23 -0800139// Test that an initial offer with one data channel generates one data media
140// section.
141TEST_F(PeerConnectionJsepTest, DataOnlyInitialOffer) {
142 auto caller = CreatePeerConnection();
143 caller->CreateDataChannel("dc");
144
145 auto offer = caller->CreateOffer();
146 auto contents = offer->description()->contents();
147 ASSERT_EQ(1u, contents.size());
148 EXPECT_EQ(cricket::MEDIA_TYPE_DATA, contents[0].media_description()->type());
149}
150
151// Test that creating multiple data channels only results in one data section
152// generated in the offer.
153TEST_F(PeerConnectionJsepTest, MultipleDataChannelsCreateOnlyOneDataSection) {
154 auto caller = CreatePeerConnection();
155 caller->CreateDataChannel("first");
156 caller->CreateDataChannel("second");
157 caller->CreateDataChannel("third");
158
159 auto offer = caller->CreateOffer();
160 ASSERT_EQ(1u, offer->description()->contents().size());
161}
162
Steve Antondcc3c022017-12-22 16:02:54 -0800163// Test that multiple media sections in the initial offer are ordered in the
164// order the transceivers were added to the PeerConnection. This is required by
165// JSEP section 5.2.1.
166TEST_F(PeerConnectionJsepTest, MediaSectionsInInitialOfferOrderedCorrectly) {
167 auto caller = CreatePeerConnection();
168 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
169 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
170 RtpTransceiverInit init;
171 init.direction = RtpTransceiverDirection::kSendOnly;
172 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init);
Steve Antondcc3c022017-12-22 16:02:54 -0800173
Steve Antonfa2260d2017-12-28 16:38:23 -0800174 auto offer = caller->CreateOffer();
Steve Antondcc3c022017-12-22 16:02:54 -0800175 auto contents = offer->description()->contents();
176 ASSERT_EQ(3u, contents.size());
177
178 const MediaContentDescription* media_description1 =
179 contents[0].media_description();
180 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, media_description1->type());
181 EXPECT_EQ(RtpTransceiverDirection::kSendRecv,
182 media_description1->direction());
183
184 const MediaContentDescription* media_description2 =
185 contents[1].media_description();
186 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, media_description2->type());
187 EXPECT_EQ(RtpTransceiverDirection::kSendRecv,
188 media_description2->direction());
189
190 const MediaContentDescription* media_description3 =
191 contents[2].media_description();
192 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, media_description3->type());
193 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
194 media_description3->direction());
195}
196
197// Test that media sections in the initial offer have different mids.
198TEST_F(PeerConnectionJsepTest, MediaSectionsInInitialOfferHaveDifferentMids) {
199 auto caller = CreatePeerConnection();
200 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
201 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
Steve Antonfa2260d2017-12-28 16:38:23 -0800202
Steve Antondcc3c022017-12-22 16:02:54 -0800203 auto offer = caller->CreateOffer();
Steve Antondcc3c022017-12-22 16:02:54 -0800204 auto contents = offer->description()->contents();
205 ASSERT_EQ(2u, contents.size());
206 EXPECT_NE(contents[0].name, contents[1].name);
207}
208
209TEST_F(PeerConnectionJsepTest,
210 StoppedTransceiverHasNoMediaSectionInInitialOffer) {
211 auto caller = CreatePeerConnection();
212 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
213 transceiver->Stop();
214
215 auto offer = caller->CreateOffer();
216 EXPECT_EQ(0u, offer->description()->contents().size());
217}
218
219// Tests for JSEP SetLocalDescription with a local offer.
220
221TEST_F(PeerConnectionJsepTest, SetLocalEmptyOfferCreatesNoTransceivers) {
222 auto caller = CreatePeerConnection();
Steve Antonfa2260d2017-12-28 16:38:23 -0800223
Steve Antondcc3c022017-12-22 16:02:54 -0800224 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
225
226 EXPECT_THAT(caller->pc()->GetTransceivers(), ElementsAre());
227 EXPECT_THAT(caller->pc()->GetSenders(), ElementsAre());
228 EXPECT_THAT(caller->pc()->GetReceivers(), ElementsAre());
229}
230
231TEST_F(PeerConnectionJsepTest, SetLocalOfferSetsTransceiverMid) {
232 auto caller = CreatePeerConnection();
233 auto audio_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
234 auto video_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
235
236 auto offer = caller->CreateOffer();
237 std::string audio_mid = offer->description()->contents()[0].name;
238 std::string video_mid = offer->description()->contents()[1].name;
239
240 ASSERT_TRUE(caller->SetLocalDescription(std::move(offer)));
241
242 EXPECT_EQ(audio_mid, audio_transceiver->mid());
243 EXPECT_EQ(video_mid, video_transceiver->mid());
244}
245
246// Tests for JSEP SetRemoteDescription with a remote offer.
247
248// Test that setting a remote offer with sendrecv audio and video creates two
249// transceivers, one for receiving audio and one for receiving video.
250TEST_F(PeerConnectionJsepTest, SetRemoteOfferCreatesTransceivers) {
251 auto caller = CreatePeerConnection();
252 auto caller_audio = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
253 auto caller_video = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
254 auto callee = CreatePeerConnection();
255
256 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
257
258 auto transceivers = callee->pc()->GetTransceivers();
259 ASSERT_EQ(2u, transceivers.size());
260 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO,
261 transceivers[0]->receiver()->media_type());
262 EXPECT_EQ(caller_audio->mid(), transceivers[0]->mid());
263 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly, transceivers[0]->direction());
264 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO,
265 transceivers[1]->receiver()->media_type());
266 EXPECT_EQ(caller_video->mid(), transceivers[1]->mid());
267 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly, transceivers[1]->direction());
268}
269
270// Test that setting a remote offer with an audio track will reuse the
271// transceiver created for a local audio track added by AddTrack.
272// This is specified in JSEP section 5.10 (Applying a Remote Description). The
273// intent is to preserve backwards compatibility with clients who only use the
274// AddTrack API.
275TEST_F(PeerConnectionJsepTest, SetRemoteOfferReusesTransceiverFromAddTrack) {
276 auto caller = CreatePeerConnection();
277 caller->AddAudioTrack("a");
278 auto caller_audio = caller->pc()->GetTransceivers()[0];
279 auto callee = CreatePeerConnection();
280 callee->AddAudioTrack("a");
281
282 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
283
284 auto transceivers = callee->pc()->GetTransceivers();
285 ASSERT_EQ(1u, transceivers.size());
286 EXPECT_EQ(MediaStreamTrackInterface::kAudioKind,
287 transceivers[0]->receiver()->track()->kind());
288 EXPECT_EQ(caller_audio->mid(), transceivers[0]->mid());
289}
290
291// Test that setting a remote offer with an audio track marked sendonly will not
292// reuse a transceiver created by AddTrack. JSEP only allows the transceiver to
293// be reused if the offer direction is sendrecv or recvonly.
294TEST_F(PeerConnectionJsepTest,
295 SetRemoteOfferDoesNotReuseTransceiverIfDirectionSendOnly) {
296 auto caller = CreatePeerConnection();
297 caller->AddAudioTrack("a");
298 auto caller_audio = caller->pc()->GetTransceivers()[0];
299 caller_audio->SetDirection(RtpTransceiverDirection::kSendOnly);
300 auto callee = CreatePeerConnection();
301 callee->AddAudioTrack("a");
302
303 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
304
305 auto transceivers = callee->pc()->GetTransceivers();
306 ASSERT_EQ(2u, transceivers.size());
307 EXPECT_EQ(rtc::nullopt, transceivers[0]->mid());
308 EXPECT_EQ(caller_audio->mid(), transceivers[1]->mid());
309}
310
311// Test that setting a remote offer with an audio track will not reuse a
312// transceiver added by AddTransceiver. The logic for reusing a transceiver is
313// specific to those added by AddTrack and is tested above.
314TEST_F(PeerConnectionJsepTest,
315 SetRemoteOfferDoesNotReuseTransceiverFromAddTransceiver) {
316 auto caller = CreatePeerConnection();
317 caller->AddAudioTrack("a");
318 auto callee = CreatePeerConnection();
319 auto transceiver = callee->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
320
321 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
322
323 auto transceivers = callee->pc()->GetTransceivers();
324 ASSERT_EQ(2u, transceivers.size());
325 EXPECT_EQ(rtc::nullopt, transceivers[0]->mid());
326 EXPECT_EQ(caller->pc()->GetTransceivers()[0]->mid(), transceivers[1]->mid());
327 EXPECT_EQ(MediaStreamTrackInterface::kAudioKind,
328 transceivers[1]->receiver()->track()->kind());
329}
330
331// Test that setting a remote offer with an audio track will not reuse a
332// transceiver created for a local video track added by AddTrack.
333TEST_F(PeerConnectionJsepTest,
334 SetRemoteOfferDoesNotReuseTransceiverOfWrongType) {
335 auto caller = CreatePeerConnection();
336 caller->AddAudioTrack("a");
337 auto callee = CreatePeerConnection();
338 auto video_sender = callee->AddVideoTrack("v");
339
340 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
341
342 auto transceivers = callee->pc()->GetTransceivers();
343 ASSERT_EQ(2u, transceivers.size());
344 EXPECT_EQ(rtc::nullopt, transceivers[0]->mid());
345 EXPECT_EQ(caller->pc()->GetTransceivers()[0]->mid(), transceivers[1]->mid());
346 EXPECT_EQ(MediaStreamTrackInterface::kAudioKind,
347 transceivers[1]->receiver()->track()->kind());
348}
349
350// Test that setting a remote offer with an audio track will not reuse a
351// stopped transceiver.
352TEST_F(PeerConnectionJsepTest, SetRemoteOfferDoesNotReuseStoppedTransceiver) {
353 auto caller = CreatePeerConnection();
354 caller->AddAudioTrack("a");
355 auto callee = CreatePeerConnection();
356 callee->AddAudioTrack("a");
357 callee->pc()->GetTransceivers()[0]->Stop();
358
359 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
360
361 auto transceivers = callee->pc()->GetTransceivers();
362 ASSERT_EQ(2u, transceivers.size());
363 EXPECT_EQ(rtc::nullopt, transceivers[0]->mid());
364 EXPECT_TRUE(transceivers[0]->stopped());
365 EXPECT_EQ(caller->pc()->GetTransceivers()[0]->mid(), transceivers[1]->mid());
366 EXPECT_FALSE(transceivers[1]->stopped());
367}
368
369// Test that audio and video transceivers created on the remote side with
370// AddTrack will all be reused if there is the same number of audio/video tracks
371// in the remote offer. Additionally, this tests that transceivers are
372// successfully matched even if they are in a different order on the remote
373// side.
374TEST_F(PeerConnectionJsepTest, SetRemoteOfferReusesTransceiversOfBothTypes) {
375 auto caller = CreatePeerConnection();
376 caller->AddVideoTrack("v");
377 caller->AddAudioTrack("a");
378 auto callee = CreatePeerConnection();
379 callee->AddAudioTrack("a");
380 callee->AddVideoTrack("v");
381
382 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
383
384 auto caller_transceivers = caller->pc()->GetTransceivers();
385 auto callee_transceivers = callee->pc()->GetTransceivers();
386 ASSERT_EQ(2u, callee_transceivers.size());
387 EXPECT_EQ(caller_transceivers[0]->mid(), callee_transceivers[1]->mid());
388 EXPECT_EQ(caller_transceivers[1]->mid(), callee_transceivers[0]->mid());
389}
390
391// Tests for JSEP initial CreateAnswer.
392
393// Test that the answer to a remote offer creates media sections for each
394// offered media in the same order and with the same mids.
395TEST_F(PeerConnectionJsepTest, CreateAnswerHasSameMidsAsOffer) {
396 auto caller = CreatePeerConnection();
397 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
398 auto second_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
399 auto third_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
Steve Antonfa2260d2017-12-28 16:38:23 -0800400 caller->CreateDataChannel("dc");
Steve Antondcc3c022017-12-22 16:02:54 -0800401 auto callee = CreatePeerConnection();
402
Steve Antonfa2260d2017-12-28 16:38:23 -0800403 auto offer = caller->CreateOffer();
404 const auto* offer_data = cricket::GetFirstDataContent(offer->description());
405 ASSERT_TRUE(
406 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
407 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
Steve Antondcc3c022017-12-22 16:02:54 -0800408
409 auto answer = callee->CreateAnswer();
410 auto contents = answer->description()->contents();
Steve Antonfa2260d2017-12-28 16:38:23 -0800411 ASSERT_EQ(4u, contents.size());
Steve Antondcc3c022017-12-22 16:02:54 -0800412 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, contents[0].media_description()->type());
Steve Antonfa2260d2017-12-28 16:38:23 -0800413 EXPECT_EQ(first_transceiver->mid(), contents[0].name);
Steve Antondcc3c022017-12-22 16:02:54 -0800414 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, contents[1].media_description()->type());
Steve Antonfa2260d2017-12-28 16:38:23 -0800415 EXPECT_EQ(second_transceiver->mid(), contents[1].name);
Steve Antondcc3c022017-12-22 16:02:54 -0800416 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, contents[2].media_description()->type());
Steve Antonfa2260d2017-12-28 16:38:23 -0800417 EXPECT_EQ(third_transceiver->mid(), contents[2].name);
418 EXPECT_EQ(cricket::MEDIA_TYPE_DATA, contents[3].media_description()->type());
419 EXPECT_EQ(offer_data->name, contents[3].name);
Steve Antondcc3c022017-12-22 16:02:54 -0800420}
421
422// Test that an answering media section is marked as rejected if the underlying
423// transceiver has been stopped.
424TEST_F(PeerConnectionJsepTest, CreateAnswerRejectsStoppedTransceiver) {
425 auto caller = CreatePeerConnection();
426 caller->AddAudioTrack("a");
427 auto callee = CreatePeerConnection();
428
429 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
430
431 callee->pc()->GetTransceivers()[0]->Stop();
432
433 auto answer = callee->CreateAnswer();
434 auto contents = answer->description()->contents();
435 ASSERT_EQ(1u, contents.size());
436 EXPECT_TRUE(contents[0].rejected);
437}
438
439// Test that CreateAnswer will generate media sections which will only send or
440// receive if the offer indicates it can do the reciprocating direction.
441// The full matrix is tested more extensively in MediaSession.
442TEST_F(PeerConnectionJsepTest, CreateAnswerNegotiatesDirection) {
443 auto caller = CreatePeerConnection();
444 RtpTransceiverInit init;
445 init.direction = RtpTransceiverDirection::kSendOnly;
446 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init);
447 auto callee = CreatePeerConnection();
448 callee->AddAudioTrack("a");
449
450 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
451
452 auto answer = callee->CreateAnswer();
453 auto contents = answer->description()->contents();
454 ASSERT_EQ(1u, contents.size());
455 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
456 contents[0].media_description()->direction());
457}
458
459// Tests for JSEP SetLocalDescription with a local answer.
460// Note that these test only the additional behaviors not covered by
461// SetLocalDescription with a local offer.
462
463// Test that SetLocalDescription with an answer sets the current_direction
464// property of the transceivers mentioned in the session description.
465TEST_F(PeerConnectionJsepTest, SetLocalAnswerUpdatesCurrentDirection) {
466 auto caller = CreatePeerConnection();
467 auto caller_audio = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
468 caller_audio->SetDirection(RtpTransceiverDirection::kRecvOnly);
469 auto callee = CreatePeerConnection();
470 callee->AddAudioTrack("a");
471
472 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
473 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
474
475 auto transceivers = callee->pc()->GetTransceivers();
476 ASSERT_EQ(1u, transceivers.size());
477 // Since the offer was recvonly and the transceiver direction is sendrecv,
478 // the negotiated direction will be sendonly.
479 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
480 transceivers[0]->current_direction());
481}
482
483// Tests for JSEP SetRemoteDescription with a remote answer.
484// Note that these test only the additional behaviors not covered by
485// SetRemoteDescription with a remote offer.
486
487TEST_F(PeerConnectionJsepTest, SetRemoteAnswerUpdatesCurrentDirection) {
488 auto caller = CreatePeerConnection();
489 caller->AddAudioTrack("a");
490 auto callee = CreatePeerConnection();
491 callee->AddAudioTrack("a");
492 auto callee_audio = callee->pc()->GetTransceivers()[0];
493 callee_audio->SetDirection(RtpTransceiverDirection::kSendOnly);
494
495 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
496 ASSERT_TRUE(
497 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
498
499 auto transceivers = caller->pc()->GetTransceivers();
500 ASSERT_EQ(1u, transceivers.size());
501 // Since the remote transceiver was set to sendonly, the negotiated direction
502 // in the answer would be sendonly which we apply as recvonly to the local
503 // transceiver.
504 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
505 transceivers[0]->current_direction());
506}
507
508// Tests for multiple round trips.
509
510// Test that setting a transceiver with the inactive direction does not stop it
511// on either the caller or the callee.
512TEST_F(PeerConnectionJsepTest, SettingTransceiverInactiveDoesNotStopIt) {
513 auto caller = CreatePeerConnection();
514 caller->AddAudioTrack("a");
515 auto callee = CreatePeerConnection();
516 callee->AddAudioTrack("a");
517 callee->pc()->GetTransceivers()[0]->SetDirection(
518 RtpTransceiverDirection::kInactive);
519
520 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
521 ASSERT_TRUE(
522 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
523
524 EXPECT_FALSE(caller->pc()->GetTransceivers()[0]->stopped());
525 EXPECT_FALSE(callee->pc()->GetTransceivers()[0]->stopped());
526}
527
528// Test that if a transceiver had been associated and later stopped, then a
529// media section is still generated for it and the media section is marked as
530// rejected.
531TEST_F(PeerConnectionJsepTest,
532 ReOfferMediaSectionForAssociatedStoppedTransceiverIsRejected) {
533 auto caller = CreatePeerConnection();
534 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
535 auto callee = CreatePeerConnection();
536
537 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
538 ASSERT_TRUE(
539 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
540
541 ASSERT_TRUE(transceiver->mid());
542 transceiver->Stop();
543
544 auto reoffer = caller->CreateOffer();
545 auto contents = reoffer->description()->contents();
546 ASSERT_EQ(1u, contents.size());
547 EXPECT_TRUE(contents[0].rejected);
548}
549
550// Test that stopping an associated transceiver on the caller side will stop the
551// corresponding transceiver on the remote side when the remote offer is
552// applied.
553TEST_F(PeerConnectionJsepTest,
554 StoppingTransceiverInOfferStopsTransceiverOnRemoteSide) {
555 auto caller = CreatePeerConnection();
556 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
557 auto callee = CreatePeerConnection();
558
559 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
560 ASSERT_TRUE(
561 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
562
563 transceiver->Stop();
564
565 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
566
567 auto transceivers = callee->pc()->GetTransceivers();
568 EXPECT_TRUE(transceivers[0]->stopped());
569 EXPECT_TRUE(transceivers[0]->mid());
570}
571
572// Test that CreateOffer will only generate a recycled media section if the
573// transceiver to be recycled has been seen stopped by the other side first.
574TEST_F(PeerConnectionJsepTest,
575 CreateOfferDoesNotRecycleMediaSectionIfFirstStopped) {
576 auto caller = CreatePeerConnection();
577 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
578 auto callee = CreatePeerConnection();
579
580 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
581 ASSERT_TRUE(
582 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
583
584 auto second_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
585 first_transceiver->Stop();
586
587 auto reoffer = caller->CreateOffer();
588 auto contents = reoffer->description()->contents();
589 ASSERT_EQ(2u, contents.size());
590 EXPECT_TRUE(contents[0].rejected);
591 EXPECT_FALSE(contents[1].rejected);
592}
593
594// Test that the offer/answer and transceivers for both the caller and callee
595// side are generated/updated correctly when recycling an audio/video media
596// section as a media section of either the same or opposite type.
597class RecycleMediaSectionTest
598 : public PeerConnectionJsepTest,
599 public testing::WithParamInterface<
600 std::tuple<cricket::MediaType, cricket::MediaType>> {
601 protected:
602 RecycleMediaSectionTest() {
603 first_type_ = std::get<0>(GetParam());
604 second_type_ = std::get<1>(GetParam());
605 }
606
607 cricket::MediaType first_type_;
608 cricket::MediaType second_type_;
609};
610
611TEST_P(RecycleMediaSectionTest, VerifyOfferAnswerAndTransceivers) {
612 auto caller = CreatePeerConnection();
613 auto first_transceiver = caller->AddTransceiver(first_type_);
614 auto callee = CreatePeerConnection();
615
616 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
617
618 std::string first_mid = *first_transceiver->mid();
619 first_transceiver->Stop();
620
621 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
622
623 auto second_transceiver = caller->AddTransceiver(second_type_);
624
625 // The offer should reuse the previous media section but allocate a new MID
626 // and change the media type.
627 auto offer = caller->CreateOffer();
628 auto offer_contents = offer->description()->contents();
629 ASSERT_EQ(1u, offer_contents.size());
630 EXPECT_FALSE(offer_contents[0].rejected);
631 EXPECT_EQ(second_type_, offer_contents[0].media_description()->type());
632 std::string second_mid = offer_contents[0].name;
633 EXPECT_NE(first_mid, second_mid);
634
635 // Setting the local offer will dissociate the previous transceiver and set
636 // the MID for the new transceiver.
637 ASSERT_TRUE(
638 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
639 EXPECT_EQ(rtc::nullopt, first_transceiver->mid());
640 EXPECT_EQ(second_mid, second_transceiver->mid());
641
642 // Setting the remote offer will dissociate the previous transceiver and
643 // create a new transceiver for the media section.
644 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
645 auto callee_transceivers = callee->pc()->GetTransceivers();
646 ASSERT_EQ(2u, callee_transceivers.size());
647 EXPECT_EQ(rtc::nullopt, callee_transceivers[0]->mid());
648 EXPECT_EQ(first_type_, callee_transceivers[0]->receiver()->media_type());
649 EXPECT_EQ(second_mid, callee_transceivers[1]->mid());
650 EXPECT_EQ(second_type_, callee_transceivers[1]->receiver()->media_type());
651
652 // The answer should have only one media section for the new transceiver.
653 auto answer = callee->CreateAnswer();
654 auto answer_contents = answer->description()->contents();
655 ASSERT_EQ(1u, answer_contents.size());
656 EXPECT_FALSE(answer_contents[0].rejected);
657 EXPECT_EQ(second_mid, answer_contents[0].name);
658 EXPECT_EQ(second_type_, answer_contents[0].media_description()->type());
659
660 // Setting the local answer should succeed.
661 ASSERT_TRUE(
662 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
663
664 // Setting the remote answer should succeed.
665 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
666}
667
668// Test all combinations of audio and video as the first and second media type
669// for the media section. This is needed for full test coverage because
670// MediaSession has separate functions for processing audio and video media
671// sections.
672INSTANTIATE_TEST_CASE_P(
673 PeerConnectionJsepTest,
674 RecycleMediaSectionTest,
675 Combine(Values(cricket::MEDIA_TYPE_AUDIO, cricket::MEDIA_TYPE_VIDEO),
676 Values(cricket::MEDIA_TYPE_AUDIO, cricket::MEDIA_TYPE_VIDEO)));
677
Steve Antonfa2260d2017-12-28 16:38:23 -0800678// Test that a new data channel section will not reuse a recycleable audio or
679// video media section. Additionally, tests that the new section is added to the
680// end of the session description.
681TEST_F(PeerConnectionJsepTest, DataChannelDoesNotRecycleMediaSection) {
682 auto caller = CreatePeerConnection();
683 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
684 auto callee = CreatePeerConnection();
685
686 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
687
688 transceiver->Stop();
689
690 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
691
692 caller->CreateDataChannel("dc");
693
694 auto offer = caller->CreateOffer();
695 auto offer_contents = offer->description()->contents();
696 ASSERT_EQ(2u, offer_contents.size());
697 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO,
698 offer_contents[0].media_description()->type());
699 EXPECT_EQ(cricket::MEDIA_TYPE_DATA,
700 offer_contents[1].media_description()->type());
701
702 ASSERT_TRUE(
703 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
704 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
705
706 auto answer = callee->CreateAnswer();
707 auto answer_contents = answer->description()->contents();
708 ASSERT_EQ(2u, answer_contents.size());
709 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO,
710 answer_contents[0].media_description()->type());
711 EXPECT_EQ(cricket::MEDIA_TYPE_DATA,
712 answer_contents[1].media_description()->type());
713}
714
715// Test that if a new track is added to an existing session that has a data,
716// the new section comes at the end of the new offer, after the existing data
717// section.
718TEST_F(PeerConnectionJsepTest, AudioTrackAddedAfterDataSectionInReoffer) {
719 auto caller = CreatePeerConnection();
720 caller->CreateDataChannel("dc");
721 auto callee = CreatePeerConnection();
722
723 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
724
725 caller->AddAudioTrack("a");
726
727 auto offer = caller->CreateOffer();
728 auto contents = offer->description()->contents();
729 ASSERT_EQ(2u, contents.size());
730 EXPECT_EQ(cricket::MEDIA_TYPE_DATA, contents[0].media_description()->type());
731 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, contents[1].media_description()->type());
732}
733
Steve Antondcc3c022017-12-22 16:02:54 -0800734// Tests for MID properties.
735
736static void RenameSection(size_t mline_index,
737 const std::string& new_mid,
738 SessionDescriptionInterface* sdesc) {
739 cricket::SessionDescription* desc = sdesc->description();
740 std::string old_mid = desc->contents()[mline_index].name;
741 desc->contents()[mline_index].name = new_mid;
742 desc->transport_infos()[mline_index].content_name = new_mid;
743 const cricket::ContentGroup* bundle =
744 desc->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
745 if (bundle) {
746 cricket::ContentGroup new_bundle = *bundle;
747 if (new_bundle.RemoveContentName(old_mid)) {
748 new_bundle.AddContentName(new_mid);
749 }
750 desc->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
751 desc->AddGroup(new_bundle);
752 }
753}
754
755// Test that two PeerConnections can have a successful offer/answer exchange if
756// the MIDs are changed from the defaults.
757TEST_F(PeerConnectionJsepTest, OfferAnswerWithChangedMids) {
758 constexpr char kFirstMid[] = "nondefaultmid";
759 constexpr char kSecondMid[] = "randommid";
760
761 auto caller = CreatePeerConnection();
762 caller->AddAudioTrack("a");
763 caller->AddAudioTrack("b");
764 auto callee = CreatePeerConnection();
765
766 auto offer = caller->CreateOffer();
767 RenameSection(0, kFirstMid, offer.get());
768 RenameSection(1, kSecondMid, offer.get());
769
770 ASSERT_TRUE(
771 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
772 auto caller_transceivers = caller->pc()->GetTransceivers();
773 EXPECT_EQ(kFirstMid, caller_transceivers[0]->mid());
774 EXPECT_EQ(kSecondMid, caller_transceivers[1]->mid());
775
776 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
777 auto callee_transceivers = callee->pc()->GetTransceivers();
778 EXPECT_EQ(kFirstMid, callee_transceivers[0]->mid());
779 EXPECT_EQ(kSecondMid, callee_transceivers[1]->mid());
780
781 auto answer = callee->CreateAnswer();
782 auto answer_contents = answer->description()->contents();
783 EXPECT_EQ(kFirstMid, answer_contents[0].name);
784 EXPECT_EQ(kSecondMid, answer_contents[1].name);
785
786 ASSERT_TRUE(
787 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
788 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
789}
790
791// Test that CreateOffer will generate a MID that is not already used if the
792// default it would have picked is already taken. This is tested by using a
793// third PeerConnection to determine what the default would be for the second
794// media section then setting that as the first media section's MID.
795TEST_F(PeerConnectionJsepTest, CreateOfferGeneratesUniqueMidIfAlreadyTaken) {
796 // First, find what the default MID is for the second media section.
797 auto pc = CreatePeerConnection();
798 pc->AddAudioTrack("a");
799 pc->AddAudioTrack("b");
800 auto default_offer = pc->CreateOffer();
801 std::string default_second_mid =
802 default_offer->description()->contents()[1].name;
803
804 // Now, do an offer/answer with one track which has the MID set to the default
805 // second MID.
806 auto caller = CreatePeerConnection();
807 caller->AddAudioTrack("a");
808 auto callee = CreatePeerConnection();
809
810 auto offer = caller->CreateOffer();
811 RenameSection(0, default_second_mid, offer.get());
812
813 ASSERT_TRUE(
814 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
815 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
816 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
817
818 // Add a second track and ensure that the MID is different.
819 caller->AddAudioTrack("b");
820
821 auto reoffer = caller->CreateOffer();
822 auto reoffer_contents = reoffer->description()->contents();
823 EXPECT_EQ(default_second_mid, reoffer_contents[0].name);
824 EXPECT_NE(reoffer_contents[0].name, reoffer_contents[1].name);
825}
826
Steve Antonfa2260d2017-12-28 16:38:23 -0800827// Test that if an audio or video section has the default data section MID, then
828// CreateOffer will generate a unique MID for the newly added data section.
829TEST_F(PeerConnectionJsepTest,
830 CreateOfferGeneratesUniqueMidForDataSectionIfAlreadyTaken) {
831 // First, find what the default MID is for the data channel.
832 auto pc = CreatePeerConnection();
833 pc->CreateDataChannel("dc");
834 auto default_offer = pc->CreateOffer();
835 std::string default_data_mid =
836 default_offer->description()->contents()[0].name;
837
838 // Now do an offer/answer with one audio track which has a MID set to the
839 // default data MID.
840 auto caller = CreatePeerConnection();
841 caller->AddAudioTrack("a");
842 auto callee = CreatePeerConnection();
843
844 auto offer = caller->CreateOffer();
845 RenameSection(0, default_data_mid, offer.get());
846
847 ASSERT_TRUE(
848 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
849 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
850 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
851
852 // Add a data channel and ensure that the MID is different.
853 caller->CreateDataChannel("dc");
854
855 auto reoffer = caller->CreateOffer();
856 auto reoffer_contents = reoffer->description()->contents();
857 EXPECT_EQ(default_data_mid, reoffer_contents[0].name);
858 EXPECT_NE(reoffer_contents[0].name, reoffer_contents[1].name);
859}
860
Steve Antondcc3c022017-12-22 16:02:54 -0800861// Test that a reoffer initiated by the callee adds a new track to the caller.
862TEST_F(PeerConnectionJsepTest, CalleeDoesReoffer) {
863 auto caller = CreatePeerConnection();
864 caller->AddAudioTrack("a");
865 auto callee = CreatePeerConnection();
866 callee->AddAudioTrack("a");
867 callee->AddVideoTrack("v");
868
869 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
870
871 EXPECT_EQ(1u, caller->pc()->GetTransceivers().size());
872 EXPECT_EQ(2u, callee->pc()->GetTransceivers().size());
873
874 ASSERT_TRUE(callee->ExchangeOfferAnswerWith(caller.get()));
875
876 EXPECT_EQ(2u, caller->pc()->GetTransceivers().size());
877 EXPECT_EQ(2u, callee->pc()->GetTransceivers().size());
878}
879
Steve Anton02ee47c2018-01-10 16:26:06 -0800880// Tests for MSID properties.
881
882// Test that adding a track with AddTrack results in an offer that signals the
883// track's ID.
884TEST_F(PeerConnectionJsepTest, AddingTrackWithAddTrackSpecifiesTrackId) {
885 const std::string kTrackId = "audio_track";
886
887 auto caller = CreatePeerConnection();
888 caller->AddAudioTrack(kTrackId);
889
890 auto offer = caller->CreateOffer();
891 auto contents = offer->description()->contents();
892 ASSERT_EQ(1u, contents.size());
893 auto streams = contents[0].media_description()->streams();
894 ASSERT_EQ(1u, streams.size());
895 EXPECT_EQ(kTrackId, streams[0].id);
896}
897
898// Test that adding a track by calling AddTransceiver then SetTrack results in
899// an offer that does not signal the track's ID and signals a random ID.
900TEST_F(PeerConnectionJsepTest,
901 AddingTrackWithAddTransceiverSpecifiesRandomTrackId) {
902 const std::string kTrackId = "audio_track";
903
904 auto caller = CreatePeerConnection();
905 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
906 transceiver->sender()->SetTrack(caller->CreateAudioTrack(kTrackId));
907
908 auto offer = caller->CreateOffer();
909 auto contents = offer->description()->contents();
910 ASSERT_EQ(1u, contents.size());
911 auto streams = contents[0].media_description()->streams();
912 ASSERT_EQ(1u, streams.size());
913 EXPECT_NE(kTrackId, streams[0].id);
914}
915
Steve Anton5f94aa22018-02-01 10:58:30 -0800916// Test that if the transceiver is recvonly or inactive, then no MSID
917// information is included in the offer.
918TEST_F(PeerConnectionJsepTest, NoMsidInOfferIfTransceiverDirectionHasNoSend) {
919 auto caller = CreatePeerConnection();
920
921 RtpTransceiverInit init_recvonly;
922 init_recvonly.direction = RtpTransceiverDirection::kRecvOnly;
923 ASSERT_TRUE(caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init_recvonly));
924
925 RtpTransceiverInit init_inactive;
926 init_inactive.direction = RtpTransceiverDirection::kInactive;
927 ASSERT_TRUE(caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init_inactive));
928
929 auto offer = caller->CreateOffer();
930 auto contents = offer->description()->contents();
931 ASSERT_EQ(2u, contents.size());
932 // MSID is specified in the first stream, so no streams means no MSID.
933 EXPECT_EQ(0u, contents[0].media_description()->streams().size());
934 EXPECT_EQ(0u, contents[1].media_description()->streams().size());
935}
936
937// Test that if an answer negotiates transceiver directions of recvonly or
938// inactive, then no MSID information is included in the answer.
939TEST_F(PeerConnectionJsepTest, NoMsidInAnswerIfNoRespondingTracks) {
940 auto caller = CreatePeerConnection();
941 auto callee = CreatePeerConnection();
942
943 // recvonly transceiver will get negotiated to inactive since the callee has
944 // no tracks to send in response.
945 RtpTransceiverInit init_recvonly;
946 init_recvonly.direction = RtpTransceiverDirection::kRecvOnly;
947 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init_recvonly);
948
949 // sendrecv transceiver will get negotiated to recvonly since the callee has
950 // no tracks to send in response.
951 RtpTransceiverInit init_sendrecv;
952 init_sendrecv.direction = RtpTransceiverDirection::kSendRecv;
953 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init_sendrecv);
954
955 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
956
957 auto answer = callee->CreateAnswer();
958 auto contents = answer->description()->contents();
959 ASSERT_EQ(2u, contents.size());
960 // MSID is specified in the first stream, so no streams means no MSID.
961 EXPECT_EQ(0u, contents[0].media_description()->streams().size());
962 EXPECT_EQ(0u, contents[1].media_description()->streams().size());
963}
964
965// Test that the MSID is included even if the transceiver direction has changed
966// to inactive if the transceiver had previously sent media.
967TEST_F(PeerConnectionJsepTest, IncludeMsidEvenIfDirectionHasChanged) {
968 auto caller = CreatePeerConnection();
969 caller->AddAudioTrack("audio");
970 auto callee = CreatePeerConnection();
971 callee->AddAudioTrack("audio");
972
973 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
974
975 caller->pc()->GetTransceivers()[0]->SetDirection(
976 RtpTransceiverDirection::kInactive);
977
978 // The transceiver direction on both sides will turn to inactive.
979 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
980
981 auto* offer = callee->pc()->remote_description();
982 auto offer_contents = offer->description()->contents();
983 ASSERT_EQ(1u, offer_contents.size());
984 // MSID is specified in the first stream. If it is present, assume that MSID
985 // is there.
986 EXPECT_EQ(1u, offer_contents[0].media_description()->streams().size());
987
988 auto* answer = caller->pc()->remote_description();
989 auto answer_contents = answer->description()->contents();
990 ASSERT_EQ(1u, answer_contents.size());
991 EXPECT_EQ(1u, answer_contents[0].media_description()->streams().size());
992}
993
994// Test that stopping a RtpTransceiver will cause future offers to not include
995// any MSID information for that section.
996TEST_F(PeerConnectionJsepTest, RemoveMsidIfTransceiverStopped) {
997 auto caller = CreatePeerConnection();
998 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
999 auto callee = CreatePeerConnection();
1000
1001 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1002
1003 transceiver->Stop();
1004
1005 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1006
1007 auto* offer = callee->pc()->remote_description();
1008 auto offer_contents = offer->description()->contents();
1009 ASSERT_EQ(1u, offer_contents.size());
1010 // MSID is specified in the first stream, so no streams means no MSID.
1011 EXPECT_EQ(0u, offer_contents[0].media_description()->streams().size());
1012}
1013
Steve Anton02ee47c2018-01-10 16:26:06 -08001014// Test that the callee RtpReceiver created by a call to SetRemoteDescription
1015// has its ID set to the signaled track ID.
1016TEST_F(PeerConnectionJsepTest,
1017 RtpReceiverCreatedBySetRemoteDescriptionHasSignaledTrackId) {
1018 const std::string kTrackId = "audio_track";
1019
1020 auto caller = CreatePeerConnection();
1021 auto callee = CreatePeerConnection();
1022 caller->AddAudioTrack(kTrackId);
1023
1024 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1025
1026 ASSERT_EQ(1u, callee->pc()->GetReceivers().size());
1027 auto receiver = callee->pc()->GetReceivers()[0];
1028 EXPECT_EQ(kTrackId, receiver->id());
1029}
1030
1031// Test that if the callee RtpReceiver is reused by a call to
1032// SetRemoteDescription, its ID does not change.
1033TEST_F(PeerConnectionJsepTest,
1034 RtpReceiverCreatedBeforeSetRemoteDescriptionKeepsId) {
1035 const std::string kTrackId = "audio_track";
1036
1037 auto caller = CreatePeerConnection();
1038 auto callee = CreatePeerConnection();
1039 caller->AddAudioTrack(kTrackId);
1040 callee->AddAudioTrack("dummy_track");
1041
1042 ASSERT_EQ(1u, callee->pc()->GetReceivers().size());
1043 auto receiver = callee->pc()->GetReceivers()[0];
1044 std::string receiver_id = receiver->id();
1045
1046 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1047
1048 EXPECT_EQ(receiver_id, receiver->id());
1049}
1050
Steve Antonef65ef12018-01-10 17:15:20 -08001051// Test that setting a remote offer with one track that has no streams fires off
1052// the correct OnAddTrack event.
1053TEST_F(PeerConnectionJsepTest,
1054 SetRemoteOfferWithOneTrackNoStreamFiresOnAddTrack) {
1055 const std::string kTrackLabel = "audio_track";
1056
1057 auto caller = CreatePeerConnection();
1058 auto callee = CreatePeerConnection();
1059 ASSERT_TRUE(caller->AddAudioTrack(kTrackLabel));
1060
1061 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1062
1063 ASSERT_EQ(callee->observer()->add_track_events_.size(), 1u);
1064 EXPECT_EQ(kTrackLabel,
1065 callee->observer()->add_track_events_[0].receiver->track()->id());
1066 // TODO(bugs.webrtc.org/7933): Also verify that no stream was added to the
1067 // receiver.
1068}
1069
1070// Test that setting a remote offer with one track that has one stream fires off
1071// the correct OnAddTrack event.
1072TEST_F(PeerConnectionJsepTest,
1073 SetRemoteOfferWithOneTrackOneStreamFiresOnAddTrack) {
1074 const std::string kTrackLabel = "audio_track";
1075 const std::string kStreamLabel = "audio_stream";
1076
1077 auto caller = CreatePeerConnection();
1078 auto callee = CreatePeerConnection();
1079 ASSERT_TRUE(caller->AddAudioTrack(kTrackLabel, {kStreamLabel}));
1080
1081 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1082
1083 const auto& track_events = callee->observer()->add_track_events_;
1084 ASSERT_EQ(1u, track_events.size());
1085 const auto& event = track_events[0];
1086 ASSERT_EQ(1u, event.streams.size());
1087 auto stream = event.streams[0];
1088 EXPECT_EQ(kStreamLabel, stream->label());
1089 EXPECT_THAT(track_events[0].snapshotted_stream_tracks.at(stream),
1090 ElementsAre(event.receiver->track()));
1091 EXPECT_EQ(event.receiver->streams(), track_events[0].streams);
1092}
1093
1094// Test that setting a remote offer with two tracks that share the same stream
1095// fires off two OnAddTrack events, both with the same stream that has both
1096// tracks present at the time of firing. This is to ensure that track events are
1097// not fired until SetRemoteDescription has finished processing all the media
1098// sections.
1099TEST_F(PeerConnectionJsepTest,
1100 SetRemoteOfferWithTwoTracksSameStreamFiresOnAddTrack) {
1101 const std::string kTrack1Label = "audio_track1";
1102 const std::string kTrack2Label = "audio_track2";
1103 const std::string kSharedStreamLabel = "stream";
1104
1105 auto caller = CreatePeerConnection();
1106 auto callee = CreatePeerConnection();
1107 ASSERT_TRUE(caller->AddAudioTrack(kTrack1Label, {kSharedStreamLabel}));
1108 ASSERT_TRUE(caller->AddAudioTrack(kTrack2Label, {kSharedStreamLabel}));
1109
1110 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1111
1112 const auto& track_events = callee->observer()->add_track_events_;
1113 ASSERT_EQ(2u, track_events.size());
1114 const auto& event1 = track_events[0];
1115 const auto& event2 = track_events[1];
1116 ASSERT_EQ(1u, event1.streams.size());
1117 auto stream = event1.streams[0];
1118 ASSERT_THAT(event2.streams, ElementsAre(stream));
1119 auto track1 = event1.receiver->track();
1120 auto track2 = event2.receiver->track();
1121 EXPECT_THAT(event1.snapshotted_stream_tracks.at(stream),
1122 UnorderedElementsAre(track1, track2));
1123 EXPECT_THAT(event2.snapshotted_stream_tracks.at(stream),
1124 UnorderedElementsAre(track1, track2));
1125}
1126
1127// TODO(bugs.webrtc.org/7932): Also test multi-stream case.
1128
Steve Antondcc3c022017-12-22 16:02:54 -08001129} // namespace webrtc