blob: 514374bbff2d53862d2a594be18e9d696553c52c [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
Mirko Bonadei317a1f02019-09-17 17:06:18 +020011#include <memory>
12
Danil Chapovalov9da25bd2019-06-20 10:19:42 +020013#include "api/task_queue/default_task_queue_factory.h"
Steve Anton10542f22019-01-11 09:11:00 -080014#include "media/engine/webrtc_media_engine.h"
Danil Chapovalov9da25bd2019-06-20 10:19:42 +020015#include "media/engine/webrtc_media_engine_defaults.h"
Steve Anton10542f22019-01-11 09:11:00 -080016#include "pc/media_session.h"
17#include "pc/peer_connection_factory.h"
18#include "pc/peer_connection_wrapper.h"
19#include "pc/sdp_utils.h"
Steve Antondcc3c022017-12-22 16:02:54 -080020#ifdef WEBRTC_ANDROID
Steve Anton10542f22019-01-11 09:11:00 -080021#include "pc/test/android_test_initializer.h"
Steve Antondcc3c022017-12-22 16:02:54 -080022#endif
Steve Anton10542f22019-01-11 09:11:00 -080023#include "pc/test/fake_audio_capture_module.h"
24#include "pc/test/fake_sctp_transport.h"
Steve Antondcc3c022017-12-22 16:02:54 -080025#include "rtc_base/gunit.h"
Steve Anton10542f22019-01-11 09:11:00 -080026#include "rtc_base/virtual_socket_server.h"
Steve Antondcc3c022017-12-22 16:02:54 -080027#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;
Steve Antondcc3c022017-12-22 16:02:54 -080039using ::testing::Combine;
40using ::testing::ElementsAre;
Steve Antonef65ef12018-01-10 17:15:20 -080041using ::testing::UnorderedElementsAre;
Jonas Olssona4d87372019-07-05 19:08:33 +020042using ::testing::Values;
Steve Antondcc3c022017-12-22 16:02:54 -080043
Steve Antonfa2260d2017-12-28 16:38:23 -080044class PeerConnectionFactoryForJsepTest : public PeerConnectionFactory {
45 public:
46 PeerConnectionFactoryForJsepTest()
Danil Chapovalovf5258be2019-03-19 17:45:24 +010047 : PeerConnectionFactory([] {
48 PeerConnectionFactoryDependencies dependencies;
49 dependencies.worker_thread = rtc::Thread::Current();
50 dependencies.network_thread = rtc::Thread::Current();
51 dependencies.signaling_thread = rtc::Thread::Current();
Danil Chapovalov9da25bd2019-06-20 10:19:42 +020052 dependencies.task_queue_factory = CreateDefaultTaskQueueFactory();
53 cricket::MediaEngineDependencies media_deps;
54 media_deps.task_queue_factory = dependencies.task_queue_factory.get();
55 media_deps.adm = FakeAudioCaptureModule::Create();
56 SetMediaEngineDefaults(&media_deps);
57 dependencies.media_engine =
58 cricket::CreateMediaEngine(std::move(media_deps));
Danil Chapovalovf5258be2019-03-19 17:45:24 +010059 dependencies.call_factory = CreateCallFactory();
60 return dependencies;
61 }()) {}
Steve Antonfa2260d2017-12-28 16:38:23 -080062
63 std::unique_ptr<cricket::SctpTransportInternalFactory>
64 CreateSctpTransportInternalFactory() {
Mirko Bonadei317a1f02019-09-17 17:06:18 +020065 return std::make_unique<FakeSctpTransportFactory>();
Steve Antonfa2260d2017-12-28 16:38:23 -080066 }
67};
68
Steve Antondcc3c022017-12-22 16:02:54 -080069class PeerConnectionJsepTest : public ::testing::Test {
70 protected:
71 typedef std::unique_ptr<PeerConnectionWrapper> WrapperPtr;
72
73 PeerConnectionJsepTest()
74 : vss_(new rtc::VirtualSocketServer()), main_(vss_.get()) {
75#ifdef WEBRTC_ANDROID
76 InitializeAndroidObjects();
77#endif
Steve Antondcc3c022017-12-22 16:02:54 -080078 }
79
80 WrapperPtr CreatePeerConnection() {
81 RTCConfiguration config;
82 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
83 return CreatePeerConnection(config);
84 }
85
86 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
Steve Antonfa2260d2017-12-28 16:38:23 -080087 rtc::scoped_refptr<PeerConnectionFactory> pc_factory(
88 new rtc::RefCountedObject<PeerConnectionFactoryForJsepTest>());
89 RTC_CHECK(pc_factory->Initialize());
Mirko Bonadei317a1f02019-09-17 17:06:18 +020090 auto observer = std::make_unique<MockPeerConnectionObserver>();
Steve Antonfa2260d2017-12-28 16:38:23 -080091 auto pc = pc_factory->CreatePeerConnection(config, nullptr, nullptr,
92 observer.get());
Steve Antondcc3c022017-12-22 16:02:54 -080093 if (!pc) {
94 return nullptr;
95 }
96
Yves Gerey4e933292018-10-31 15:36:05 +010097 observer->SetPeerConnectionInterface(pc.get());
Mirko Bonadei317a1f02019-09-17 17:06:18 +020098 return std::make_unique<PeerConnectionWrapper>(pc_factory, pc,
99 std::move(observer));
Steve Antondcc3c022017-12-22 16:02:54 -0800100 }
101
102 std::unique_ptr<rtc::VirtualSocketServer> vss_;
103 rtc::AutoSocketServerThread main_;
Steve Antondcc3c022017-12-22 16:02:54 -0800104};
105
106// Tests for JSEP initial offer generation.
107
108// Test that an offer created by a PeerConnection with no transceivers generates
109// no media sections.
110TEST_F(PeerConnectionJsepTest, EmptyInitialOffer) {
111 auto caller = CreatePeerConnection();
Steve Antonfa2260d2017-12-28 16:38:23 -0800112
Steve Antondcc3c022017-12-22 16:02:54 -0800113 auto offer = caller->CreateOffer();
Steve Antonfa2260d2017-12-28 16:38:23 -0800114 ASSERT_EQ(0u, offer->description()->contents().size());
Steve Antondcc3c022017-12-22 16:02:54 -0800115}
116
117// Test that an initial offer with one audio track generates one audio media
118// section.
119TEST_F(PeerConnectionJsepTest, AudioOnlyInitialOffer) {
120 auto caller = CreatePeerConnection();
121 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
Steve Antondcc3c022017-12-22 16:02:54 -0800122
Steve Antonfa2260d2017-12-28 16:38:23 -0800123 auto offer = caller->CreateOffer();
Steve Antondcc3c022017-12-22 16:02:54 -0800124 auto contents = offer->description()->contents();
125 ASSERT_EQ(1u, contents.size());
126 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, contents[0].media_description()->type());
127}
128
129// Test than an initial offer with one video track generates one video media
130// section
131TEST_F(PeerConnectionJsepTest, VideoOnlyInitialOffer) {
132 auto caller = CreatePeerConnection();
133 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
Steve Antondcc3c022017-12-22 16:02:54 -0800134
Steve Antonfa2260d2017-12-28 16:38:23 -0800135 auto offer = caller->CreateOffer();
Steve Antondcc3c022017-12-22 16:02:54 -0800136 auto contents = offer->description()->contents();
137 ASSERT_EQ(1u, contents.size());
138 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, contents[0].media_description()->type());
139}
140
Steve Antonfa2260d2017-12-28 16:38:23 -0800141// Test that an initial offer with one data channel generates one data media
142// section.
143TEST_F(PeerConnectionJsepTest, DataOnlyInitialOffer) {
144 auto caller = CreatePeerConnection();
145 caller->CreateDataChannel("dc");
146
147 auto offer = caller->CreateOffer();
148 auto contents = offer->description()->contents();
149 ASSERT_EQ(1u, contents.size());
150 EXPECT_EQ(cricket::MEDIA_TYPE_DATA, contents[0].media_description()->type());
151}
152
153// Test that creating multiple data channels only results in one data section
154// generated in the offer.
155TEST_F(PeerConnectionJsepTest, MultipleDataChannelsCreateOnlyOneDataSection) {
156 auto caller = CreatePeerConnection();
157 caller->CreateDataChannel("first");
158 caller->CreateDataChannel("second");
159 caller->CreateDataChannel("third");
160
161 auto offer = caller->CreateOffer();
162 ASSERT_EQ(1u, offer->description()->contents().size());
163}
164
Steve Antondcc3c022017-12-22 16:02:54 -0800165// Test that multiple media sections in the initial offer are ordered in the
166// order the transceivers were added to the PeerConnection. This is required by
167// JSEP section 5.2.1.
168TEST_F(PeerConnectionJsepTest, MediaSectionsInInitialOfferOrderedCorrectly) {
169 auto caller = CreatePeerConnection();
170 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
171 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
172 RtpTransceiverInit init;
173 init.direction = RtpTransceiverDirection::kSendOnly;
174 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init);
Steve Antondcc3c022017-12-22 16:02:54 -0800175
Steve Antonfa2260d2017-12-28 16:38:23 -0800176 auto offer = caller->CreateOffer();
Steve Antondcc3c022017-12-22 16:02:54 -0800177 auto contents = offer->description()->contents();
178 ASSERT_EQ(3u, contents.size());
179
180 const MediaContentDescription* media_description1 =
181 contents[0].media_description();
182 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, media_description1->type());
183 EXPECT_EQ(RtpTransceiverDirection::kSendRecv,
184 media_description1->direction());
185
186 const MediaContentDescription* media_description2 =
187 contents[1].media_description();
188 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, media_description2->type());
189 EXPECT_EQ(RtpTransceiverDirection::kSendRecv,
190 media_description2->direction());
191
192 const MediaContentDescription* media_description3 =
193 contents[2].media_description();
194 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, media_description3->type());
195 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
196 media_description3->direction());
197}
198
199// Test that media sections in the initial offer have different mids.
200TEST_F(PeerConnectionJsepTest, MediaSectionsInInitialOfferHaveDifferentMids) {
201 auto caller = CreatePeerConnection();
202 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
203 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
Steve Antonfa2260d2017-12-28 16:38:23 -0800204
Steve Antondcc3c022017-12-22 16:02:54 -0800205 auto offer = caller->CreateOffer();
Steve Antondcc3c022017-12-22 16:02:54 -0800206 auto contents = offer->description()->contents();
207 ASSERT_EQ(2u, contents.size());
208 EXPECT_NE(contents[0].name, contents[1].name);
209}
210
211TEST_F(PeerConnectionJsepTest,
212 StoppedTransceiverHasNoMediaSectionInInitialOffer) {
213 auto caller = CreatePeerConnection();
214 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
215 transceiver->Stop();
216
217 auto offer = caller->CreateOffer();
218 EXPECT_EQ(0u, offer->description()->contents().size());
219}
220
221// Tests for JSEP SetLocalDescription with a local offer.
222
223TEST_F(PeerConnectionJsepTest, SetLocalEmptyOfferCreatesNoTransceivers) {
224 auto caller = CreatePeerConnection();
Steve Antonfa2260d2017-12-28 16:38:23 -0800225
Steve Antondcc3c022017-12-22 16:02:54 -0800226 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
227
228 EXPECT_THAT(caller->pc()->GetTransceivers(), ElementsAre());
229 EXPECT_THAT(caller->pc()->GetSenders(), ElementsAre());
230 EXPECT_THAT(caller->pc()->GetReceivers(), ElementsAre());
231}
232
233TEST_F(PeerConnectionJsepTest, SetLocalOfferSetsTransceiverMid) {
234 auto caller = CreatePeerConnection();
235 auto audio_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
236 auto video_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
237
238 auto offer = caller->CreateOffer();
239 std::string audio_mid = offer->description()->contents()[0].name;
240 std::string video_mid = offer->description()->contents()[1].name;
241
242 ASSERT_TRUE(caller->SetLocalDescription(std::move(offer)));
243
244 EXPECT_EQ(audio_mid, audio_transceiver->mid());
245 EXPECT_EQ(video_mid, video_transceiver->mid());
246}
247
248// Tests for JSEP SetRemoteDescription with a remote offer.
249
250// Test that setting a remote offer with sendrecv audio and video creates two
251// transceivers, one for receiving audio and one for receiving video.
252TEST_F(PeerConnectionJsepTest, SetRemoteOfferCreatesTransceivers) {
253 auto caller = CreatePeerConnection();
254 auto caller_audio = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
255 auto caller_video = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
256 auto callee = CreatePeerConnection();
257
258 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
259
260 auto transceivers = callee->pc()->GetTransceivers();
261 ASSERT_EQ(2u, transceivers.size());
Steve Anton1bc97162018-06-25 14:04:01 -0700262
Steve Anton69470252018-02-09 11:43:08 -0800263 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, transceivers[0]->media_type());
Steve Antondcc3c022017-12-22 16:02:54 -0800264 EXPECT_EQ(caller_audio->mid(), transceivers[0]->mid());
265 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly, transceivers[0]->direction());
Steve Anton1bc97162018-06-25 14:04:01 -0700266 EXPECT_EQ(0u, transceivers[0]->sender()->stream_ids().size());
267
Steve Anton69470252018-02-09 11:43:08 -0800268 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, transceivers[1]->media_type());
Steve Antondcc3c022017-12-22 16:02:54 -0800269 EXPECT_EQ(caller_video->mid(), transceivers[1]->mid());
270 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly, transceivers[1]->direction());
Steve Anton1bc97162018-06-25 14:04:01 -0700271 EXPECT_EQ(0u, transceivers[1]->sender()->stream_ids().size());
Steve Antondcc3c022017-12-22 16:02:54 -0800272}
273
274// Test that setting a remote offer with an audio track will reuse the
275// transceiver created for a local audio track added by AddTrack.
276// This is specified in JSEP section 5.10 (Applying a Remote Description). The
277// intent is to preserve backwards compatibility with clients who only use the
278// AddTrack API.
279TEST_F(PeerConnectionJsepTest, SetRemoteOfferReusesTransceiverFromAddTrack) {
280 auto caller = CreatePeerConnection();
281 caller->AddAudioTrack("a");
282 auto caller_audio = caller->pc()->GetTransceivers()[0];
283 auto callee = CreatePeerConnection();
284 callee->AddAudioTrack("a");
285
286 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
287
288 auto transceivers = callee->pc()->GetTransceivers();
289 ASSERT_EQ(1u, transceivers.size());
290 EXPECT_EQ(MediaStreamTrackInterface::kAudioKind,
291 transceivers[0]->receiver()->track()->kind());
292 EXPECT_EQ(caller_audio->mid(), transceivers[0]->mid());
293}
294
295// Test that setting a remote offer with an audio track marked sendonly will not
296// reuse a transceiver created by AddTrack. JSEP only allows the transceiver to
297// be reused if the offer direction is sendrecv or recvonly.
298TEST_F(PeerConnectionJsepTest,
299 SetRemoteOfferDoesNotReuseTransceiverIfDirectionSendOnly) {
300 auto caller = CreatePeerConnection();
301 caller->AddAudioTrack("a");
302 auto caller_audio = caller->pc()->GetTransceivers()[0];
303 caller_audio->SetDirection(RtpTransceiverDirection::kSendOnly);
304 auto callee = CreatePeerConnection();
305 callee->AddAudioTrack("a");
306
307 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
308
309 auto transceivers = callee->pc()->GetTransceivers();
310 ASSERT_EQ(2u, transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200311 EXPECT_EQ(absl::nullopt, transceivers[0]->mid());
Steve Antondcc3c022017-12-22 16:02:54 -0800312 EXPECT_EQ(caller_audio->mid(), transceivers[1]->mid());
313}
314
315// Test that setting a remote offer with an audio track will not reuse a
316// transceiver added by AddTransceiver. The logic for reusing a transceiver is
317// specific to those added by AddTrack and is tested above.
318TEST_F(PeerConnectionJsepTest,
319 SetRemoteOfferDoesNotReuseTransceiverFromAddTransceiver) {
320 auto caller = CreatePeerConnection();
321 caller->AddAudioTrack("a");
322 auto callee = CreatePeerConnection();
323 auto transceiver = callee->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
324
325 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
326
327 auto transceivers = callee->pc()->GetTransceivers();
328 ASSERT_EQ(2u, transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200329 EXPECT_EQ(absl::nullopt, transceivers[0]->mid());
Steve Antondcc3c022017-12-22 16:02:54 -0800330 EXPECT_EQ(caller->pc()->GetTransceivers()[0]->mid(), transceivers[1]->mid());
331 EXPECT_EQ(MediaStreamTrackInterface::kAudioKind,
332 transceivers[1]->receiver()->track()->kind());
333}
334
335// Test that setting a remote offer with an audio track will not reuse a
336// transceiver created for a local video track added by AddTrack.
337TEST_F(PeerConnectionJsepTest,
338 SetRemoteOfferDoesNotReuseTransceiverOfWrongType) {
339 auto caller = CreatePeerConnection();
340 caller->AddAudioTrack("a");
341 auto callee = CreatePeerConnection();
342 auto video_sender = callee->AddVideoTrack("v");
343
344 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
345
346 auto transceivers = callee->pc()->GetTransceivers();
347 ASSERT_EQ(2u, transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200348 EXPECT_EQ(absl::nullopt, transceivers[0]->mid());
Steve Antondcc3c022017-12-22 16:02:54 -0800349 EXPECT_EQ(caller->pc()->GetTransceivers()[0]->mid(), transceivers[1]->mid());
350 EXPECT_EQ(MediaStreamTrackInterface::kAudioKind,
351 transceivers[1]->receiver()->track()->kind());
352}
353
354// Test that setting a remote offer with an audio track will not reuse a
355// stopped transceiver.
356TEST_F(PeerConnectionJsepTest, SetRemoteOfferDoesNotReuseStoppedTransceiver) {
357 auto caller = CreatePeerConnection();
358 caller->AddAudioTrack("a");
359 auto callee = CreatePeerConnection();
360 callee->AddAudioTrack("a");
361 callee->pc()->GetTransceivers()[0]->Stop();
362
363 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
364
365 auto transceivers = callee->pc()->GetTransceivers();
366 ASSERT_EQ(2u, transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200367 EXPECT_EQ(absl::nullopt, transceivers[0]->mid());
Steve Antondcc3c022017-12-22 16:02:54 -0800368 EXPECT_TRUE(transceivers[0]->stopped());
369 EXPECT_EQ(caller->pc()->GetTransceivers()[0]->mid(), transceivers[1]->mid());
370 EXPECT_FALSE(transceivers[1]->stopped());
371}
372
373// Test that audio and video transceivers created on the remote side with
374// AddTrack will all be reused if there is the same number of audio/video tracks
375// in the remote offer. Additionally, this tests that transceivers are
376// successfully matched even if they are in a different order on the remote
377// side.
378TEST_F(PeerConnectionJsepTest, SetRemoteOfferReusesTransceiversOfBothTypes) {
379 auto caller = CreatePeerConnection();
380 caller->AddVideoTrack("v");
381 caller->AddAudioTrack("a");
382 auto callee = CreatePeerConnection();
383 callee->AddAudioTrack("a");
384 callee->AddVideoTrack("v");
385
386 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
387
388 auto caller_transceivers = caller->pc()->GetTransceivers();
389 auto callee_transceivers = callee->pc()->GetTransceivers();
390 ASSERT_EQ(2u, callee_transceivers.size());
391 EXPECT_EQ(caller_transceivers[0]->mid(), callee_transceivers[1]->mid());
392 EXPECT_EQ(caller_transceivers[1]->mid(), callee_transceivers[0]->mid());
393}
394
395// Tests for JSEP initial CreateAnswer.
396
397// Test that the answer to a remote offer creates media sections for each
398// offered media in the same order and with the same mids.
399TEST_F(PeerConnectionJsepTest, CreateAnswerHasSameMidsAsOffer) {
400 auto caller = CreatePeerConnection();
401 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
402 auto second_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
403 auto third_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
Steve Antonfa2260d2017-12-28 16:38:23 -0800404 caller->CreateDataChannel("dc");
Steve Antondcc3c022017-12-22 16:02:54 -0800405 auto callee = CreatePeerConnection();
406
Steve Antonfa2260d2017-12-28 16:38:23 -0800407 auto offer = caller->CreateOffer();
408 const auto* offer_data = cricket::GetFirstDataContent(offer->description());
409 ASSERT_TRUE(
410 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
411 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
Steve Antondcc3c022017-12-22 16:02:54 -0800412
413 auto answer = callee->CreateAnswer();
414 auto contents = answer->description()->contents();
Steve Antonfa2260d2017-12-28 16:38:23 -0800415 ASSERT_EQ(4u, contents.size());
Steve Antondcc3c022017-12-22 16:02:54 -0800416 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, contents[0].media_description()->type());
Steve Antonfa2260d2017-12-28 16:38:23 -0800417 EXPECT_EQ(first_transceiver->mid(), contents[0].name);
Steve Antondcc3c022017-12-22 16:02:54 -0800418 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, contents[1].media_description()->type());
Steve Antonfa2260d2017-12-28 16:38:23 -0800419 EXPECT_EQ(second_transceiver->mid(), contents[1].name);
Steve Antondcc3c022017-12-22 16:02:54 -0800420 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, contents[2].media_description()->type());
Steve Antonfa2260d2017-12-28 16:38:23 -0800421 EXPECT_EQ(third_transceiver->mid(), contents[2].name);
422 EXPECT_EQ(cricket::MEDIA_TYPE_DATA, contents[3].media_description()->type());
423 EXPECT_EQ(offer_data->name, contents[3].name);
Steve Antondcc3c022017-12-22 16:02:54 -0800424}
425
426// Test that an answering media section is marked as rejected if the underlying
427// transceiver has been stopped.
428TEST_F(PeerConnectionJsepTest, CreateAnswerRejectsStoppedTransceiver) {
429 auto caller = CreatePeerConnection();
430 caller->AddAudioTrack("a");
431 auto callee = CreatePeerConnection();
432
433 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
434
435 callee->pc()->GetTransceivers()[0]->Stop();
436
437 auto answer = callee->CreateAnswer();
438 auto contents = answer->description()->contents();
439 ASSERT_EQ(1u, contents.size());
440 EXPECT_TRUE(contents[0].rejected);
441}
442
443// Test that CreateAnswer will generate media sections which will only send or
444// receive if the offer indicates it can do the reciprocating direction.
445// The full matrix is tested more extensively in MediaSession.
446TEST_F(PeerConnectionJsepTest, CreateAnswerNegotiatesDirection) {
447 auto caller = CreatePeerConnection();
448 RtpTransceiverInit init;
449 init.direction = RtpTransceiverDirection::kSendOnly;
450 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init);
451 auto callee = CreatePeerConnection();
452 callee->AddAudioTrack("a");
453
454 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
455
456 auto answer = callee->CreateAnswer();
457 auto contents = answer->description()->contents();
458 ASSERT_EQ(1u, contents.size());
459 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
460 contents[0].media_description()->direction());
461}
462
463// Tests for JSEP SetLocalDescription with a local answer.
464// Note that these test only the additional behaviors not covered by
465// SetLocalDescription with a local offer.
466
467// Test that SetLocalDescription with an answer sets the current_direction
468// property of the transceivers mentioned in the session description.
469TEST_F(PeerConnectionJsepTest, SetLocalAnswerUpdatesCurrentDirection) {
470 auto caller = CreatePeerConnection();
471 auto caller_audio = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
472 caller_audio->SetDirection(RtpTransceiverDirection::kRecvOnly);
473 auto callee = CreatePeerConnection();
474 callee->AddAudioTrack("a");
475
476 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
477 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
478
479 auto transceivers = callee->pc()->GetTransceivers();
480 ASSERT_EQ(1u, transceivers.size());
481 // Since the offer was recvonly and the transceiver direction is sendrecv,
482 // the negotiated direction will be sendonly.
483 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
484 transceivers[0]->current_direction());
485}
486
487// Tests for JSEP SetRemoteDescription with a remote answer.
488// Note that these test only the additional behaviors not covered by
489// SetRemoteDescription with a remote offer.
490
491TEST_F(PeerConnectionJsepTest, SetRemoteAnswerUpdatesCurrentDirection) {
492 auto caller = CreatePeerConnection();
493 caller->AddAudioTrack("a");
494 auto callee = CreatePeerConnection();
495 callee->AddAudioTrack("a");
496 auto callee_audio = callee->pc()->GetTransceivers()[0];
497 callee_audio->SetDirection(RtpTransceiverDirection::kSendOnly);
498
499 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
500 ASSERT_TRUE(
501 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
502
503 auto transceivers = caller->pc()->GetTransceivers();
504 ASSERT_EQ(1u, transceivers.size());
505 // Since the remote transceiver was set to sendonly, the negotiated direction
506 // in the answer would be sendonly which we apply as recvonly to the local
507 // transceiver.
508 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
509 transceivers[0]->current_direction());
510}
511
512// Tests for multiple round trips.
513
514// Test that setting a transceiver with the inactive direction does not stop it
515// on either the caller or the callee.
516TEST_F(PeerConnectionJsepTest, SettingTransceiverInactiveDoesNotStopIt) {
517 auto caller = CreatePeerConnection();
518 caller->AddAudioTrack("a");
519 auto callee = CreatePeerConnection();
520 callee->AddAudioTrack("a");
521 callee->pc()->GetTransceivers()[0]->SetDirection(
522 RtpTransceiverDirection::kInactive);
523
524 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
525 ASSERT_TRUE(
526 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
527
528 EXPECT_FALSE(caller->pc()->GetTransceivers()[0]->stopped());
529 EXPECT_FALSE(callee->pc()->GetTransceivers()[0]->stopped());
530}
531
532// Test that if a transceiver had been associated and later stopped, then a
533// media section is still generated for it and the media section is marked as
534// rejected.
535TEST_F(PeerConnectionJsepTest,
536 ReOfferMediaSectionForAssociatedStoppedTransceiverIsRejected) {
537 auto caller = CreatePeerConnection();
538 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
539 auto callee = CreatePeerConnection();
540
541 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
542 ASSERT_TRUE(
543 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
544
545 ASSERT_TRUE(transceiver->mid());
546 transceiver->Stop();
547
548 auto reoffer = caller->CreateOffer();
549 auto contents = reoffer->description()->contents();
550 ASSERT_EQ(1u, contents.size());
551 EXPECT_TRUE(contents[0].rejected);
552}
553
554// Test that stopping an associated transceiver on the caller side will stop the
555// corresponding transceiver on the remote side when the remote offer is
556// applied.
557TEST_F(PeerConnectionJsepTest,
558 StoppingTransceiverInOfferStopsTransceiverOnRemoteSide) {
559 auto caller = CreatePeerConnection();
560 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
561 auto callee = CreatePeerConnection();
562
563 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
564 ASSERT_TRUE(
565 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
566
567 transceiver->Stop();
568
569 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
570
571 auto transceivers = callee->pc()->GetTransceivers();
572 EXPECT_TRUE(transceivers[0]->stopped());
573 EXPECT_TRUE(transceivers[0]->mid());
574}
575
576// Test that CreateOffer will only generate a recycled media section if the
577// transceiver to be recycled has been seen stopped by the other side first.
578TEST_F(PeerConnectionJsepTest,
579 CreateOfferDoesNotRecycleMediaSectionIfFirstStopped) {
580 auto caller = CreatePeerConnection();
581 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
582 auto callee = CreatePeerConnection();
583
584 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
585 ASSERT_TRUE(
586 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
587
588 auto second_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
589 first_transceiver->Stop();
590
591 auto reoffer = caller->CreateOffer();
592 auto contents = reoffer->description()->contents();
593 ASSERT_EQ(2u, contents.size());
594 EXPECT_TRUE(contents[0].rejected);
595 EXPECT_FALSE(contents[1].rejected);
596}
597
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800598// Test that the offer/answer and the transceivers are correctly generated and
599// updated when the media section is recycled after the callee stops a
600// transceiver and sends an answer with a 0 port.
601TEST_F(PeerConnectionJsepTest,
602 RecycleMediaSectionWhenStoppingTransceiverOnAnswerer) {
603 auto caller = CreatePeerConnection();
604 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
605 auto callee = CreatePeerConnection();
606
607 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
608 callee->pc()->GetTransceivers()[0]->Stop();
609 ASSERT_TRUE(
610 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
611 EXPECT_TRUE(first_transceiver->stopped());
612 // First transceivers aren't dissociated yet.
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200613 ASSERT_NE(absl::nullopt, first_transceiver->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800614 std::string first_mid = *first_transceiver->mid();
615 EXPECT_EQ(first_mid, callee->pc()->GetTransceivers()[0]->mid());
616
617 // New offer exchange with new transceivers that recycles the m section
618 // correctly.
619 caller->AddAudioTrack("audio2");
620 callee->AddAudioTrack("audio2");
621 auto offer = caller->CreateOffer();
622 auto offer_contents = offer->description()->contents();
623 std::string second_mid = offer_contents[0].name;
624 ASSERT_EQ(1u, offer_contents.size());
625 EXPECT_FALSE(offer_contents[0].rejected);
626 EXPECT_NE(first_mid, second_mid);
627
628 // Setting the offer on each side will dissociate the first transceivers and
629 // associate the new transceivers.
630 ASSERT_TRUE(
631 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200632 EXPECT_EQ(absl::nullopt, first_transceiver->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800633 EXPECT_EQ(second_mid, caller->pc()->GetTransceivers()[1]->mid());
634 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200635 EXPECT_EQ(absl::nullopt, callee->pc()->GetTransceivers()[0]->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800636 EXPECT_EQ(second_mid, callee->pc()->GetTransceivers()[1]->mid());
637
638 // The new answer should also recycle the m section correctly.
639 auto answer = callee->CreateAnswer();
640 auto answer_contents = answer->description()->contents();
641 ASSERT_EQ(1u, answer_contents.size());
642 EXPECT_FALSE(answer_contents[0].rejected);
643 EXPECT_EQ(second_mid, answer_contents[0].name);
644
645 // Finishing the negotiation shouldn't add or dissociate any transceivers.
646 ASSERT_TRUE(
647 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
648 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
649 auto caller_transceivers = caller->pc()->GetTransceivers();
650 ASSERT_EQ(2u, caller_transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200651 EXPECT_EQ(absl::nullopt, caller_transceivers[0]->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800652 EXPECT_EQ(second_mid, caller_transceivers[1]->mid());
653 auto callee_transceivers = callee->pc()->GetTransceivers();
654 ASSERT_EQ(2u, callee_transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200655 EXPECT_EQ(absl::nullopt, callee_transceivers[0]->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800656 EXPECT_EQ(second_mid, callee_transceivers[1]->mid());
657}
658
659// Test that creating/setting a local offer that recycles an m= section is
660// idempotent.
661TEST_F(PeerConnectionJsepTest, CreateOfferRecyclesWhenOfferingTwice) {
662 // Do a negotiation with a port 0 for the media section.
663 auto caller = CreatePeerConnection();
664 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
665 auto callee = CreatePeerConnection();
666 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
667 first_transceiver->Stop();
668 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
669 caller->AddAudioTrack("audio2");
670
671 // Create a new offer that recycles the media section and set it as a local
672 // description.
673 auto offer = caller->CreateOffer();
674 auto offer_contents = offer->description()->contents();
675 ASSERT_EQ(1u, offer_contents.size());
676 EXPECT_FALSE(offer_contents[0].rejected);
677 ASSERT_TRUE(caller->SetLocalDescription(std::move(offer)));
678 EXPECT_FALSE(caller->pc()->GetTransceivers()[1]->stopped());
679 std::string second_mid = offer_contents[0].name;
680
681 // Create another new offer and set the local description again without the
682 // rest of any negotation ocurring.
683 auto second_offer = caller->CreateOffer();
684 auto second_offer_contents = second_offer->description()->contents();
685 ASSERT_EQ(1u, second_offer_contents.size());
686 EXPECT_FALSE(second_offer_contents[0].rejected);
687 // The mid shouldn't change.
688 EXPECT_EQ(second_mid, second_offer_contents[0].name);
689
690 ASSERT_TRUE(caller->SetLocalDescription(std::move(second_offer)));
691 // Make sure that the caller's transceivers are associated correctly.
692 auto caller_transceivers = caller->pc()->GetTransceivers();
693 ASSERT_EQ(2u, caller_transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200694 EXPECT_EQ(absl::nullopt, caller_transceivers[0]->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800695 EXPECT_EQ(second_mid, caller_transceivers[1]->mid());
696 EXPECT_FALSE(caller_transceivers[1]->stopped());
697}
698
Steve Antondcc3c022017-12-22 16:02:54 -0800699// Test that the offer/answer and transceivers for both the caller and callee
700// side are generated/updated correctly when recycling an audio/video media
701// section as a media section of either the same or opposite type.
Steve Anton5c72e712018-12-10 14:25:30 -0800702// Correct recycling works as follows:
703// - The m= section is re-offered with a new MID value and the new media type.
704// - The previously-associated transceiver is dissociated when the new offer is
705// set as a local description on the offerer or as a remote description on
706// the answerer.
707// - The new transceiver is associated with the new MID value.
Steve Antondcc3c022017-12-22 16:02:54 -0800708class RecycleMediaSectionTest
709 : public PeerConnectionJsepTest,
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200710 public ::testing::WithParamInterface<
Steve Antondcc3c022017-12-22 16:02:54 -0800711 std::tuple<cricket::MediaType, cricket::MediaType>> {
712 protected:
713 RecycleMediaSectionTest() {
714 first_type_ = std::get<0>(GetParam());
715 second_type_ = std::get<1>(GetParam());
716 }
717
718 cricket::MediaType first_type_;
719 cricket::MediaType second_type_;
720};
721
Steve Anton5c72e712018-12-10 14:25:30 -0800722// Test that recycling works properly when a new transceiver recycles an m=
723// section that was rejected in both the current local and remote descriptions.
724TEST_P(RecycleMediaSectionTest, CurrentLocalAndCurrentRemoteRejected) {
Steve Antondcc3c022017-12-22 16:02:54 -0800725 auto caller = CreatePeerConnection();
726 auto first_transceiver = caller->AddTransceiver(first_type_);
727 auto callee = CreatePeerConnection();
728
729 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
730
731 std::string first_mid = *first_transceiver->mid();
732 first_transceiver->Stop();
733
734 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
735
736 auto second_transceiver = caller->AddTransceiver(second_type_);
737
738 // The offer should reuse the previous media section but allocate a new MID
739 // and change the media type.
740 auto offer = caller->CreateOffer();
741 auto offer_contents = offer->description()->contents();
742 ASSERT_EQ(1u, offer_contents.size());
743 EXPECT_FALSE(offer_contents[0].rejected);
744 EXPECT_EQ(second_type_, offer_contents[0].media_description()->type());
745 std::string second_mid = offer_contents[0].name;
746 EXPECT_NE(first_mid, second_mid);
747
748 // Setting the local offer will dissociate the previous transceiver and set
749 // the MID for the new transceiver.
750 ASSERT_TRUE(
751 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200752 EXPECT_EQ(absl::nullopt, first_transceiver->mid());
Steve Antondcc3c022017-12-22 16:02:54 -0800753 EXPECT_EQ(second_mid, second_transceiver->mid());
754
755 // Setting the remote offer will dissociate the previous transceiver and
756 // create a new transceiver for the media section.
757 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
758 auto callee_transceivers = callee->pc()->GetTransceivers();
759 ASSERT_EQ(2u, callee_transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200760 EXPECT_EQ(absl::nullopt, callee_transceivers[0]->mid());
Steve Anton69470252018-02-09 11:43:08 -0800761 EXPECT_EQ(first_type_, callee_transceivers[0]->media_type());
Steve Antondcc3c022017-12-22 16:02:54 -0800762 EXPECT_EQ(second_mid, callee_transceivers[1]->mid());
Steve Anton69470252018-02-09 11:43:08 -0800763 EXPECT_EQ(second_type_, callee_transceivers[1]->media_type());
Steve Antondcc3c022017-12-22 16:02:54 -0800764
765 // The answer should have only one media section for the new transceiver.
766 auto answer = callee->CreateAnswer();
767 auto answer_contents = answer->description()->contents();
768 ASSERT_EQ(1u, answer_contents.size());
769 EXPECT_FALSE(answer_contents[0].rejected);
770 EXPECT_EQ(second_mid, answer_contents[0].name);
771 EXPECT_EQ(second_type_, answer_contents[0].media_description()->type());
772
773 // Setting the local answer should succeed.
774 ASSERT_TRUE(
775 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
776
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800777 // Setting the remote answer should succeed and not create any new
778 // transceivers.
Steve Antondcc3c022017-12-22 16:02:54 -0800779 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800780 ASSERT_EQ(2u, caller->pc()->GetTransceivers().size());
781 ASSERT_EQ(2u, callee->pc()->GetTransceivers().size());
Steve Antondcc3c022017-12-22 16:02:54 -0800782}
783
Steve Anton5c72e712018-12-10 14:25:30 -0800784// Test that recycling works properly when a new transceiver recycles an m=
785// section that was rejected in only the current remote description.
786TEST_P(RecycleMediaSectionTest, CurrentRemoteOnlyRejected) {
787 auto caller = CreatePeerConnection();
788 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
789 auto callee = CreatePeerConnection();
790
791 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
792
793 std::string first_mid = *caller_first_transceiver->mid();
794 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
795 auto callee_first_transceiver = callee->pc()->GetTransceivers()[0];
796 callee_first_transceiver->Stop();
797
798 // The answer will have a rejected m= section.
799 ASSERT_TRUE(
800 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
801
802 // The offer should reuse the previous media section but allocate a new MID
803 // and change the media type.
804 auto caller_second_transceiver = caller->AddTransceiver(second_type_);
805 auto offer = caller->CreateOffer();
806 const auto& offer_contents = offer->description()->contents();
807 ASSERT_EQ(1u, offer_contents.size());
808 EXPECT_FALSE(offer_contents[0].rejected);
809 EXPECT_EQ(second_type_, offer_contents[0].media_description()->type());
810 std::string second_mid = offer_contents[0].name;
811 EXPECT_NE(first_mid, second_mid);
812
813 // Setting the local offer will dissociate the previous transceiver and set
814 // the MID for the new transceiver.
815 ASSERT_TRUE(
816 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
817 EXPECT_EQ(absl::nullopt, caller_first_transceiver->mid());
818 EXPECT_EQ(second_mid, caller_second_transceiver->mid());
819
820 // Setting the remote offer will dissociate the previous transceiver and
821 // create a new transceiver for the media section.
822 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
823 auto callee_transceivers = callee->pc()->GetTransceivers();
824 ASSERT_EQ(2u, callee_transceivers.size());
825 EXPECT_EQ(absl::nullopt, callee_transceivers[0]->mid());
826 EXPECT_EQ(first_type_, callee_transceivers[0]->media_type());
827 EXPECT_EQ(second_mid, callee_transceivers[1]->mid());
828 EXPECT_EQ(second_type_, callee_transceivers[1]->media_type());
829
830 // The answer should have only one media section for the new transceiver.
831 auto answer = callee->CreateAnswer();
832 auto answer_contents = answer->description()->contents();
833 ASSERT_EQ(1u, answer_contents.size());
834 EXPECT_FALSE(answer_contents[0].rejected);
835 EXPECT_EQ(second_mid, answer_contents[0].name);
836 EXPECT_EQ(second_type_, answer_contents[0].media_description()->type());
837
838 // Setting the local answer should succeed.
839 ASSERT_TRUE(
840 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
841
842 // Setting the remote answer should succeed and not create any new
843 // transceivers.
844 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
845 ASSERT_EQ(2u, caller->pc()->GetTransceivers().size());
846 ASSERT_EQ(2u, callee->pc()->GetTransceivers().size());
847}
848
849// Test that recycling works properly when a new transceiver recycles an m=
850// section that was rejected only in the current local description.
851TEST_P(RecycleMediaSectionTest, CurrentLocalOnlyRejected) {
852 auto caller = CreatePeerConnection();
853 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
854 auto callee = CreatePeerConnection();
855
856 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
857
858 std::string first_mid = *caller_first_transceiver->mid();
859 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
860 auto callee_first_transceiver = callee->pc()->GetTransceivers()[0];
861 callee_first_transceiver->Stop();
862
863 // The answer will have a rejected m= section.
864 ASSERT_TRUE(
865 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
866
867 // The offer should reuse the previous media section but allocate a new MID
868 // and change the media type.
869 auto callee_second_transceiver = callee->AddTransceiver(second_type_);
870 auto offer = callee->CreateOffer();
871 const auto& offer_contents = offer->description()->contents();
872 ASSERT_EQ(1u, offer_contents.size());
873 EXPECT_FALSE(offer_contents[0].rejected);
874 EXPECT_EQ(second_type_, offer_contents[0].media_description()->type());
875 std::string second_mid = offer_contents[0].name;
876 EXPECT_NE(first_mid, second_mid);
877
878 // Setting the local offer will dissociate the previous transceiver and set
879 // the MID for the new transceiver.
880 ASSERT_TRUE(
881 callee->SetLocalDescription(CloneSessionDescription(offer.get())));
882 EXPECT_EQ(absl::nullopt, callee_first_transceiver->mid());
883 EXPECT_EQ(second_mid, callee_second_transceiver->mid());
884
885 // Setting the remote offer will dissociate the previous transceiver and
886 // create a new transceiver for the media section.
887 ASSERT_TRUE(caller->SetRemoteDescription(std::move(offer)));
888 auto caller_transceivers = caller->pc()->GetTransceivers();
889 ASSERT_EQ(2u, caller_transceivers.size());
890 EXPECT_EQ(absl::nullopt, caller_transceivers[0]->mid());
891 EXPECT_EQ(first_type_, caller_transceivers[0]->media_type());
892 EXPECT_EQ(second_mid, caller_transceivers[1]->mid());
893 EXPECT_EQ(second_type_, caller_transceivers[1]->media_type());
894
895 // The answer should have only one media section for the new transceiver.
896 auto answer = caller->CreateAnswer();
897 auto answer_contents = answer->description()->contents();
898 ASSERT_EQ(1u, answer_contents.size());
899 EXPECT_FALSE(answer_contents[0].rejected);
900 EXPECT_EQ(second_mid, answer_contents[0].name);
901 EXPECT_EQ(second_type_, answer_contents[0].media_description()->type());
902
903 // Setting the local answer should succeed.
904 ASSERT_TRUE(
905 caller->SetLocalDescription(CloneSessionDescription(answer.get())));
906
907 // Setting the remote answer should succeed and not create any new
908 // transceivers.
909 ASSERT_TRUE(callee->SetRemoteDescription(std::move(answer)));
910 ASSERT_EQ(2u, callee->pc()->GetTransceivers().size());
911 ASSERT_EQ(2u, caller->pc()->GetTransceivers().size());
912}
913
914// Test that a m= section is *not* recycled if the media section is only
915// rejected in the pending local description and there is no current remote
916// description.
917TEST_P(RecycleMediaSectionTest, PendingLocalRejectedAndNoRemote) {
918 auto caller = CreatePeerConnection();
919 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
920
921 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
922
923 std::string first_mid = *caller_first_transceiver->mid();
924 caller_first_transceiver->Stop();
925
926 // The reoffer will have a rejected m= section.
927 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
928
929 auto caller_second_transceiver = caller->AddTransceiver(second_type_);
930
931 // The reoffer should not recycle the existing m= section since it is not
932 // rejected in either the *current* local or *current* remote description.
933 auto reoffer = caller->CreateOffer();
934 auto reoffer_contents = reoffer->description()->contents();
935 ASSERT_EQ(2u, reoffer_contents.size());
936 EXPECT_TRUE(reoffer_contents[0].rejected);
937 EXPECT_EQ(first_type_, reoffer_contents[0].media_description()->type());
938 EXPECT_EQ(first_mid, reoffer_contents[0].name);
939 EXPECT_FALSE(reoffer_contents[1].rejected);
940 EXPECT_EQ(second_type_, reoffer_contents[1].media_description()->type());
941 std::string second_mid = reoffer_contents[1].name;
942 EXPECT_NE(first_mid, second_mid);
943
944 ASSERT_TRUE(caller->SetLocalDescription(std::move(reoffer)));
945
946 // Both RtpTransceivers are associated.
947 EXPECT_EQ(first_mid, caller_first_transceiver->mid());
948 EXPECT_EQ(second_mid, caller_second_transceiver->mid());
949}
950
951// Test that a m= section is *not* recycled if the media section is only
952// rejected in the pending local description and not rejected in the current
953// remote description.
954TEST_P(RecycleMediaSectionTest, PendingLocalRejectedAndNotRejectedRemote) {
955 auto caller = CreatePeerConnection();
956 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
957 auto callee = CreatePeerConnection();
958
959 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
960
961 std::string first_mid = *caller_first_transceiver->mid();
962 caller_first_transceiver->Stop();
963
964 // The reoffer will have a rejected m= section.
965 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
966
967 auto caller_second_transceiver = caller->AddTransceiver(second_type_);
968
969 // The reoffer should not recycle the existing m= section since it is not
970 // rejected in either the *current* local or *current* remote description.
971 auto reoffer = caller->CreateOffer();
972 auto reoffer_contents = reoffer->description()->contents();
973 ASSERT_EQ(2u, reoffer_contents.size());
974 EXPECT_TRUE(reoffer_contents[0].rejected);
975 EXPECT_EQ(first_type_, reoffer_contents[0].media_description()->type());
976 EXPECT_EQ(first_mid, reoffer_contents[0].name);
977 EXPECT_FALSE(reoffer_contents[1].rejected);
978 EXPECT_EQ(second_type_, reoffer_contents[1].media_description()->type());
979 std::string second_mid = reoffer_contents[1].name;
980 EXPECT_NE(first_mid, second_mid);
981
982 ASSERT_TRUE(caller->SetLocalDescription(std::move(reoffer)));
983
984 // Both RtpTransceivers are associated.
985 EXPECT_EQ(first_mid, caller_first_transceiver->mid());
986 EXPECT_EQ(second_mid, caller_second_transceiver->mid());
987}
988
989// Test that an m= section is *not* recycled if the media section is only
990// rejected in the pending remote description and there is no current local
991// description.
992TEST_P(RecycleMediaSectionTest, PendingRemoteRejectedAndNoLocal) {
993 auto caller = CreatePeerConnection();
994 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
995 auto callee = CreatePeerConnection();
996
997 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
998
999 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
1000 auto callee_first_transceiver = callee->pc()->GetTransceivers()[0];
1001 std::string first_mid = *callee_first_transceiver->mid();
1002 caller_first_transceiver->Stop();
1003
1004 // The reoffer will have a rejected m= section.
1005 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1006
1007 auto callee_second_transceiver = callee->AddTransceiver(second_type_);
1008
1009 // The reoffer should not recycle the existing m= section since it is not
1010 // rejected in either the *current* local or *current* remote description.
1011 auto reoffer = callee->CreateOffer();
1012 auto reoffer_contents = reoffer->description()->contents();
1013 ASSERT_EQ(2u, reoffer_contents.size());
1014 EXPECT_TRUE(reoffer_contents[0].rejected);
1015 EXPECT_EQ(first_type_, reoffer_contents[0].media_description()->type());
1016 EXPECT_EQ(first_mid, reoffer_contents[0].name);
1017 EXPECT_FALSE(reoffer_contents[1].rejected);
1018 EXPECT_EQ(second_type_, reoffer_contents[1].media_description()->type());
1019 std::string second_mid = reoffer_contents[1].name;
1020 EXPECT_NE(first_mid, second_mid);
1021
1022 // Note: Cannot actually set the reoffer since the callee is in the signaling
1023 // state 'have-remote-offer'.
1024}
1025
1026// Test that an m= section is *not* recycled if the media section is only
1027// rejected in the pending remote description and not rejected in the current
1028// local description.
1029TEST_P(RecycleMediaSectionTest, PendingRemoteRejectedAndNotRejectedLocal) {
1030 auto caller = CreatePeerConnection();
1031 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
1032 auto callee = CreatePeerConnection();
1033
1034 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1035
1036 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
1037 auto callee_first_transceiver = callee->pc()->GetTransceivers()[0];
1038 std::string first_mid = *callee_first_transceiver->mid();
1039 caller_first_transceiver->Stop();
1040
1041 // The reoffer will have a rejected m= section.
1042 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1043
1044 auto callee_second_transceiver = callee->AddTransceiver(second_type_);
1045
1046 // The reoffer should not recycle the existing m= section since it is not
1047 // rejected in either the *current* local or *current* remote description.
1048 auto reoffer = callee->CreateOffer();
1049 auto reoffer_contents = reoffer->description()->contents();
1050 ASSERT_EQ(2u, reoffer_contents.size());
1051 EXPECT_TRUE(reoffer_contents[0].rejected);
1052 EXPECT_EQ(first_type_, reoffer_contents[0].media_description()->type());
1053 EXPECT_EQ(first_mid, reoffer_contents[0].name);
1054 EXPECT_FALSE(reoffer_contents[1].rejected);
1055 EXPECT_EQ(second_type_, reoffer_contents[1].media_description()->type());
1056 std::string second_mid = reoffer_contents[1].name;
1057 EXPECT_NE(first_mid, second_mid);
1058
1059 // Note: Cannot actually set the reoffer since the callee is in the signaling
1060 // state 'have-remote-offer'.
1061}
1062
Steve Antondcc3c022017-12-22 16:02:54 -08001063// Test all combinations of audio and video as the first and second media type
1064// for the media section. This is needed for full test coverage because
1065// MediaSession has separate functions for processing audio and video media
1066// sections.
Mirko Bonadeic84f6612019-01-31 12:20:57 +01001067INSTANTIATE_TEST_SUITE_P(
Steve Antondcc3c022017-12-22 16:02:54 -08001068 PeerConnectionJsepTest,
1069 RecycleMediaSectionTest,
1070 Combine(Values(cricket::MEDIA_TYPE_AUDIO, cricket::MEDIA_TYPE_VIDEO),
1071 Values(cricket::MEDIA_TYPE_AUDIO, cricket::MEDIA_TYPE_VIDEO)));
1072
Steve Antonfa2260d2017-12-28 16:38:23 -08001073// Test that a new data channel section will not reuse a recycleable audio or
1074// video media section. Additionally, tests that the new section is added to the
1075// end of the session description.
1076TEST_F(PeerConnectionJsepTest, DataChannelDoesNotRecycleMediaSection) {
1077 auto caller = CreatePeerConnection();
1078 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1079 auto callee = CreatePeerConnection();
1080
1081 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1082
1083 transceiver->Stop();
1084
1085 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1086
1087 caller->CreateDataChannel("dc");
1088
1089 auto offer = caller->CreateOffer();
1090 auto offer_contents = offer->description()->contents();
1091 ASSERT_EQ(2u, offer_contents.size());
1092 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO,
1093 offer_contents[0].media_description()->type());
1094 EXPECT_EQ(cricket::MEDIA_TYPE_DATA,
1095 offer_contents[1].media_description()->type());
1096
1097 ASSERT_TRUE(
1098 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
1099 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1100
1101 auto answer = callee->CreateAnswer();
1102 auto answer_contents = answer->description()->contents();
1103 ASSERT_EQ(2u, answer_contents.size());
1104 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO,
1105 answer_contents[0].media_description()->type());
1106 EXPECT_EQ(cricket::MEDIA_TYPE_DATA,
1107 answer_contents[1].media_description()->type());
1108}
1109
1110// Test that if a new track is added to an existing session that has a data,
1111// the new section comes at the end of the new offer, after the existing data
1112// section.
1113TEST_F(PeerConnectionJsepTest, AudioTrackAddedAfterDataSectionInReoffer) {
1114 auto caller = CreatePeerConnection();
1115 caller->CreateDataChannel("dc");
1116 auto callee = CreatePeerConnection();
1117
1118 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1119
1120 caller->AddAudioTrack("a");
1121
1122 auto offer = caller->CreateOffer();
1123 auto contents = offer->description()->contents();
1124 ASSERT_EQ(2u, contents.size());
1125 EXPECT_EQ(cricket::MEDIA_TYPE_DATA, contents[0].media_description()->type());
1126 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, contents[1].media_description()->type());
1127}
1128
Steve Antondcc3c022017-12-22 16:02:54 -08001129// Tests for MID properties.
1130
1131static void RenameSection(size_t mline_index,
1132 const std::string& new_mid,
1133 SessionDescriptionInterface* sdesc) {
1134 cricket::SessionDescription* desc = sdesc->description();
1135 std::string old_mid = desc->contents()[mline_index].name;
1136 desc->contents()[mline_index].name = new_mid;
1137 desc->transport_infos()[mline_index].content_name = new_mid;
1138 const cricket::ContentGroup* bundle =
1139 desc->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1140 if (bundle) {
1141 cricket::ContentGroup new_bundle = *bundle;
1142 if (new_bundle.RemoveContentName(old_mid)) {
1143 new_bundle.AddContentName(new_mid);
1144 }
1145 desc->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1146 desc->AddGroup(new_bundle);
1147 }
1148}
1149
1150// Test that two PeerConnections can have a successful offer/answer exchange if
1151// the MIDs are changed from the defaults.
1152TEST_F(PeerConnectionJsepTest, OfferAnswerWithChangedMids) {
1153 constexpr char kFirstMid[] = "nondefaultmid";
1154 constexpr char kSecondMid[] = "randommid";
1155
1156 auto caller = CreatePeerConnection();
1157 caller->AddAudioTrack("a");
1158 caller->AddAudioTrack("b");
1159 auto callee = CreatePeerConnection();
1160
1161 auto offer = caller->CreateOffer();
1162 RenameSection(0, kFirstMid, offer.get());
1163 RenameSection(1, kSecondMid, offer.get());
1164
1165 ASSERT_TRUE(
1166 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
1167 auto caller_transceivers = caller->pc()->GetTransceivers();
1168 EXPECT_EQ(kFirstMid, caller_transceivers[0]->mid());
1169 EXPECT_EQ(kSecondMid, caller_transceivers[1]->mid());
1170
1171 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1172 auto callee_transceivers = callee->pc()->GetTransceivers();
1173 EXPECT_EQ(kFirstMid, callee_transceivers[0]->mid());
1174 EXPECT_EQ(kSecondMid, callee_transceivers[1]->mid());
1175
1176 auto answer = callee->CreateAnswer();
1177 auto answer_contents = answer->description()->contents();
1178 EXPECT_EQ(kFirstMid, answer_contents[0].name);
1179 EXPECT_EQ(kSecondMid, answer_contents[1].name);
1180
1181 ASSERT_TRUE(
1182 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
1183 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
1184}
1185
1186// Test that CreateOffer will generate a MID that is not already used if the
1187// default it would have picked is already taken. This is tested by using a
1188// third PeerConnection to determine what the default would be for the second
1189// media section then setting that as the first media section's MID.
1190TEST_F(PeerConnectionJsepTest, CreateOfferGeneratesUniqueMidIfAlreadyTaken) {
1191 // First, find what the default MID is for the second media section.
1192 auto pc = CreatePeerConnection();
1193 pc->AddAudioTrack("a");
1194 pc->AddAudioTrack("b");
1195 auto default_offer = pc->CreateOffer();
1196 std::string default_second_mid =
1197 default_offer->description()->contents()[1].name;
1198
1199 // Now, do an offer/answer with one track which has the MID set to the default
1200 // second MID.
1201 auto caller = CreatePeerConnection();
1202 caller->AddAudioTrack("a");
1203 auto callee = CreatePeerConnection();
1204
1205 auto offer = caller->CreateOffer();
1206 RenameSection(0, default_second_mid, offer.get());
1207
1208 ASSERT_TRUE(
1209 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
1210 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1211 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1212
1213 // Add a second track and ensure that the MID is different.
1214 caller->AddAudioTrack("b");
1215
1216 auto reoffer = caller->CreateOffer();
1217 auto reoffer_contents = reoffer->description()->contents();
1218 EXPECT_EQ(default_second_mid, reoffer_contents[0].name);
1219 EXPECT_NE(reoffer_contents[0].name, reoffer_contents[1].name);
1220}
1221
Steve Antonfa2260d2017-12-28 16:38:23 -08001222// Test that if an audio or video section has the default data section MID, then
1223// CreateOffer will generate a unique MID for the newly added data section.
1224TEST_F(PeerConnectionJsepTest,
1225 CreateOfferGeneratesUniqueMidForDataSectionIfAlreadyTaken) {
1226 // First, find what the default MID is for the data channel.
1227 auto pc = CreatePeerConnection();
1228 pc->CreateDataChannel("dc");
1229 auto default_offer = pc->CreateOffer();
1230 std::string default_data_mid =
1231 default_offer->description()->contents()[0].name;
1232
1233 // Now do an offer/answer with one audio track which has a MID set to the
1234 // default data MID.
1235 auto caller = CreatePeerConnection();
1236 caller->AddAudioTrack("a");
1237 auto callee = CreatePeerConnection();
1238
1239 auto offer = caller->CreateOffer();
1240 RenameSection(0, default_data_mid, offer.get());
1241
1242 ASSERT_TRUE(
1243 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
1244 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1245 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1246
1247 // Add a data channel and ensure that the MID is different.
1248 caller->CreateDataChannel("dc");
1249
1250 auto reoffer = caller->CreateOffer();
1251 auto reoffer_contents = reoffer->description()->contents();
1252 EXPECT_EQ(default_data_mid, reoffer_contents[0].name);
1253 EXPECT_NE(reoffer_contents[0].name, reoffer_contents[1].name);
1254}
1255
Steve Antondcc3c022017-12-22 16:02:54 -08001256// Test that a reoffer initiated by the callee adds a new track to the caller.
1257TEST_F(PeerConnectionJsepTest, CalleeDoesReoffer) {
1258 auto caller = CreatePeerConnection();
1259 caller->AddAudioTrack("a");
1260 auto callee = CreatePeerConnection();
1261 callee->AddAudioTrack("a");
1262 callee->AddVideoTrack("v");
1263
1264 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1265
1266 EXPECT_EQ(1u, caller->pc()->GetTransceivers().size());
1267 EXPECT_EQ(2u, callee->pc()->GetTransceivers().size());
1268
1269 ASSERT_TRUE(callee->ExchangeOfferAnswerWith(caller.get()));
1270
1271 EXPECT_EQ(2u, caller->pc()->GetTransceivers().size());
1272 EXPECT_EQ(2u, callee->pc()->GetTransceivers().size());
1273}
1274
Steve Anton02ee47c2018-01-10 16:26:06 -08001275// Tests for MSID properties.
1276
1277// Test that adding a track with AddTrack results in an offer that signals the
1278// track's ID.
1279TEST_F(PeerConnectionJsepTest, AddingTrackWithAddTrackSpecifiesTrackId) {
1280 const std::string kTrackId = "audio_track";
1281
1282 auto caller = CreatePeerConnection();
1283 caller->AddAudioTrack(kTrackId);
1284
1285 auto offer = caller->CreateOffer();
1286 auto contents = offer->description()->contents();
1287 ASSERT_EQ(1u, contents.size());
1288 auto streams = contents[0].media_description()->streams();
1289 ASSERT_EQ(1u, streams.size());
1290 EXPECT_EQ(kTrackId, streams[0].id);
1291}
1292
1293// Test that adding a track by calling AddTransceiver then SetTrack results in
1294// an offer that does not signal the track's ID and signals a random ID.
1295TEST_F(PeerConnectionJsepTest,
1296 AddingTrackWithAddTransceiverSpecifiesRandomTrackId) {
1297 const std::string kTrackId = "audio_track";
1298
1299 auto caller = CreatePeerConnection();
1300 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1301 transceiver->sender()->SetTrack(caller->CreateAudioTrack(kTrackId));
1302
1303 auto offer = caller->CreateOffer();
1304 auto contents = offer->description()->contents();
1305 ASSERT_EQ(1u, contents.size());
1306 auto streams = contents[0].media_description()->streams();
1307 ASSERT_EQ(1u, streams.size());
1308 EXPECT_NE(kTrackId, streams[0].id);
1309}
1310
Steve Anton5f94aa22018-02-01 10:58:30 -08001311// Test that if the transceiver is recvonly or inactive, then no MSID
1312// information is included in the offer.
1313TEST_F(PeerConnectionJsepTest, NoMsidInOfferIfTransceiverDirectionHasNoSend) {
1314 auto caller = CreatePeerConnection();
1315
1316 RtpTransceiverInit init_recvonly;
1317 init_recvonly.direction = RtpTransceiverDirection::kRecvOnly;
1318 ASSERT_TRUE(caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init_recvonly));
1319
1320 RtpTransceiverInit init_inactive;
1321 init_inactive.direction = RtpTransceiverDirection::kInactive;
1322 ASSERT_TRUE(caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init_inactive));
1323
1324 auto offer = caller->CreateOffer();
1325 auto contents = offer->description()->contents();
1326 ASSERT_EQ(2u, contents.size());
1327 // MSID is specified in the first stream, so no streams means no MSID.
1328 EXPECT_EQ(0u, contents[0].media_description()->streams().size());
1329 EXPECT_EQ(0u, contents[1].media_description()->streams().size());
1330}
1331
1332// Test that if an answer negotiates transceiver directions of recvonly or
1333// inactive, then no MSID information is included in the answer.
1334TEST_F(PeerConnectionJsepTest, NoMsidInAnswerIfNoRespondingTracks) {
1335 auto caller = CreatePeerConnection();
1336 auto callee = CreatePeerConnection();
1337
1338 // recvonly transceiver will get negotiated to inactive since the callee has
1339 // no tracks to send in response.
1340 RtpTransceiverInit init_recvonly;
1341 init_recvonly.direction = RtpTransceiverDirection::kRecvOnly;
1342 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init_recvonly);
1343
1344 // sendrecv transceiver will get negotiated to recvonly since the callee has
1345 // no tracks to send in response.
1346 RtpTransceiverInit init_sendrecv;
1347 init_sendrecv.direction = RtpTransceiverDirection::kSendRecv;
1348 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init_sendrecv);
1349
1350 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1351
1352 auto answer = callee->CreateAnswer();
1353 auto contents = answer->description()->contents();
1354 ASSERT_EQ(2u, contents.size());
1355 // MSID is specified in the first stream, so no streams means no MSID.
1356 EXPECT_EQ(0u, contents[0].media_description()->streams().size());
1357 EXPECT_EQ(0u, contents[1].media_description()->streams().size());
1358}
1359
1360// Test that the MSID is included even if the transceiver direction has changed
1361// to inactive if the transceiver had previously sent media.
1362TEST_F(PeerConnectionJsepTest, IncludeMsidEvenIfDirectionHasChanged) {
1363 auto caller = CreatePeerConnection();
1364 caller->AddAudioTrack("audio");
1365 auto callee = CreatePeerConnection();
1366 callee->AddAudioTrack("audio");
1367
1368 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1369
1370 caller->pc()->GetTransceivers()[0]->SetDirection(
1371 RtpTransceiverDirection::kInactive);
1372
1373 // The transceiver direction on both sides will turn to inactive.
1374 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1375
1376 auto* offer = callee->pc()->remote_description();
1377 auto offer_contents = offer->description()->contents();
1378 ASSERT_EQ(1u, offer_contents.size());
1379 // MSID is specified in the first stream. If it is present, assume that MSID
1380 // is there.
1381 EXPECT_EQ(1u, offer_contents[0].media_description()->streams().size());
1382
1383 auto* answer = caller->pc()->remote_description();
1384 auto answer_contents = answer->description()->contents();
1385 ASSERT_EQ(1u, answer_contents.size());
1386 EXPECT_EQ(1u, answer_contents[0].media_description()->streams().size());
1387}
1388
1389// Test that stopping a RtpTransceiver will cause future offers to not include
1390// any MSID information for that section.
1391TEST_F(PeerConnectionJsepTest, RemoveMsidIfTransceiverStopped) {
1392 auto caller = CreatePeerConnection();
1393 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1394 auto callee = CreatePeerConnection();
1395
1396 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1397
1398 transceiver->Stop();
1399
1400 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1401
1402 auto* offer = callee->pc()->remote_description();
1403 auto offer_contents = offer->description()->contents();
1404 ASSERT_EQ(1u, offer_contents.size());
1405 // MSID is specified in the first stream, so no streams means no MSID.
1406 EXPECT_EQ(0u, offer_contents[0].media_description()->streams().size());
1407}
1408
Steve Anton02ee47c2018-01-10 16:26:06 -08001409// Test that the callee RtpReceiver created by a call to SetRemoteDescription
1410// has its ID set to the signaled track ID.
1411TEST_F(PeerConnectionJsepTest,
1412 RtpReceiverCreatedBySetRemoteDescriptionHasSignaledTrackId) {
1413 const std::string kTrackId = "audio_track";
1414
1415 auto caller = CreatePeerConnection();
1416 auto callee = CreatePeerConnection();
1417 caller->AddAudioTrack(kTrackId);
1418
1419 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1420
1421 ASSERT_EQ(1u, callee->pc()->GetReceivers().size());
1422 auto receiver = callee->pc()->GetReceivers()[0];
1423 EXPECT_EQ(kTrackId, receiver->id());
1424}
1425
1426// Test that if the callee RtpReceiver is reused by a call to
1427// SetRemoteDescription, its ID does not change.
1428TEST_F(PeerConnectionJsepTest,
1429 RtpReceiverCreatedBeforeSetRemoteDescriptionKeepsId) {
1430 const std::string kTrackId = "audio_track";
1431
1432 auto caller = CreatePeerConnection();
1433 auto callee = CreatePeerConnection();
1434 caller->AddAudioTrack(kTrackId);
1435 callee->AddAudioTrack("dummy_track");
1436
1437 ASSERT_EQ(1u, callee->pc()->GetReceivers().size());
1438 auto receiver = callee->pc()->GetReceivers()[0];
1439 std::string receiver_id = receiver->id();
1440
1441 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1442
1443 EXPECT_EQ(receiver_id, receiver->id());
1444}
1445
Steve Antonef65ef12018-01-10 17:15:20 -08001446// Test that setting a remote offer with one track that has no streams fires off
1447// the correct OnAddTrack event.
1448TEST_F(PeerConnectionJsepTest,
1449 SetRemoteOfferWithOneTrackNoStreamFiresOnAddTrack) {
1450 const std::string kTrackLabel = "audio_track";
1451
1452 auto caller = CreatePeerConnection();
1453 auto callee = CreatePeerConnection();
1454 ASSERT_TRUE(caller->AddAudioTrack(kTrackLabel));
1455
1456 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1457
Seth Hampson5b4f0752018-04-02 16:31:36 -07001458 const auto& track_events = callee->observer()->add_track_events_;
1459 ASSERT_EQ(1u, track_events.size());
1460 const auto& event = track_events[0];
1461 EXPECT_EQ(kTrackLabel, event.receiver->track()->id());
1462 EXPECT_EQ(0u, event.streams.size());
Steve Antonef65ef12018-01-10 17:15:20 -08001463}
1464
1465// Test that setting a remote offer with one track that has one stream fires off
1466// the correct OnAddTrack event.
1467TEST_F(PeerConnectionJsepTest,
1468 SetRemoteOfferWithOneTrackOneStreamFiresOnAddTrack) {
1469 const std::string kTrackLabel = "audio_track";
Seth Hampson845e8782018-03-02 11:34:10 -08001470 const std::string kStreamId = "audio_stream";
Steve Antonef65ef12018-01-10 17:15:20 -08001471
1472 auto caller = CreatePeerConnection();
1473 auto callee = CreatePeerConnection();
Seth Hampson845e8782018-03-02 11:34:10 -08001474 ASSERT_TRUE(caller->AddAudioTrack(kTrackLabel, {kStreamId}));
Steve Antonef65ef12018-01-10 17:15:20 -08001475
1476 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1477
1478 const auto& track_events = callee->observer()->add_track_events_;
1479 ASSERT_EQ(1u, track_events.size());
1480 const auto& event = track_events[0];
1481 ASSERT_EQ(1u, event.streams.size());
1482 auto stream = event.streams[0];
Seth Hampson13b8bad2018-03-13 16:05:28 -07001483 EXPECT_EQ(kStreamId, stream->id());
Steve Antonef65ef12018-01-10 17:15:20 -08001484 EXPECT_THAT(track_events[0].snapshotted_stream_tracks.at(stream),
1485 ElementsAre(event.receiver->track()));
1486 EXPECT_EQ(event.receiver->streams(), track_events[0].streams);
1487}
1488
1489// Test that setting a remote offer with two tracks that share the same stream
1490// fires off two OnAddTrack events, both with the same stream that has both
1491// tracks present at the time of firing. This is to ensure that track events are
1492// not fired until SetRemoteDescription has finished processing all the media
1493// sections.
1494TEST_F(PeerConnectionJsepTest,
1495 SetRemoteOfferWithTwoTracksSameStreamFiresOnAddTrack) {
1496 const std::string kTrack1Label = "audio_track1";
1497 const std::string kTrack2Label = "audio_track2";
Seth Hampson845e8782018-03-02 11:34:10 -08001498 const std::string kSharedStreamId = "stream";
Steve Antonef65ef12018-01-10 17:15:20 -08001499
1500 auto caller = CreatePeerConnection();
1501 auto callee = CreatePeerConnection();
Seth Hampson845e8782018-03-02 11:34:10 -08001502 ASSERT_TRUE(caller->AddAudioTrack(kTrack1Label, {kSharedStreamId}));
1503 ASSERT_TRUE(caller->AddAudioTrack(kTrack2Label, {kSharedStreamId}));
Steve Antonef65ef12018-01-10 17:15:20 -08001504
1505 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1506
1507 const auto& track_events = callee->observer()->add_track_events_;
1508 ASSERT_EQ(2u, track_events.size());
1509 const auto& event1 = track_events[0];
1510 const auto& event2 = track_events[1];
1511 ASSERT_EQ(1u, event1.streams.size());
1512 auto stream = event1.streams[0];
1513 ASSERT_THAT(event2.streams, ElementsAre(stream));
1514 auto track1 = event1.receiver->track();
1515 auto track2 = event2.receiver->track();
1516 EXPECT_THAT(event1.snapshotted_stream_tracks.at(stream),
1517 UnorderedElementsAre(track1, track2));
1518 EXPECT_THAT(event2.snapshotted_stream_tracks.at(stream),
1519 UnorderedElementsAre(track1, track2));
1520}
1521
Seth Hampson5b4f0752018-04-02 16:31:36 -07001522// Test that setting a remote offer with one track that has two streams fires
1523// off the correct OnAddTrack event.
1524TEST_F(PeerConnectionJsepTest,
1525 SetRemoteOfferWithOneTrackTwoStreamFiresOnAddTrack) {
1526 const std::string kTrackLabel = "audio_track";
1527 const std::string kStreamId1 = "audio_stream1";
1528 const std::string kStreamId2 = "audio_stream2";
1529
1530 auto caller = CreatePeerConnection();
1531 auto callee = CreatePeerConnection();
1532 ASSERT_TRUE(caller->AddAudioTrack(kTrackLabel, {kStreamId1, kStreamId2}));
1533
1534 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1535
1536 const auto& track_events = callee->observer()->add_track_events_;
1537 ASSERT_EQ(1u, track_events.size());
1538 const auto& event = track_events[0];
1539 ASSERT_EQ(2u, event.streams.size());
1540 EXPECT_EQ(kStreamId1, event.streams[0]->id());
1541 EXPECT_EQ(kStreamId2, event.streams[1]->id());
1542}
Steve Antonef65ef12018-01-10 17:15:20 -08001543
Steve Anton54b84072018-02-20 15:19:52 -08001544// Test that if an RtpTransceiver with a current_direction set is stopped, then
1545// current_direction is changed to null.
1546TEST_F(PeerConnectionJsepTest, CurrentDirectionResetWhenRtpTransceiverStopped) {
1547 auto caller = CreatePeerConnection();
1548 auto callee = CreatePeerConnection();
1549
1550 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1551
1552 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1553
1554 ASSERT_TRUE(transceiver->current_direction());
1555 transceiver->Stop();
1556 EXPECT_FALSE(transceiver->current_direction());
1557}
1558
Steve Antonba42e992018-04-09 14:10:01 -07001559// Test that you can't set an answer on a PeerConnection before setting the
1560// offer.
Harald Alvestrand5081c0c2018-03-09 15:18:03 +01001561TEST_F(PeerConnectionJsepTest, AnswerBeforeOfferFails) {
1562 auto caller = CreatePeerConnection();
1563 auto callee = CreatePeerConnection();
Harald Alvestrand5081c0c2018-03-09 15:18:03 +01001564 caller->AddAudioTrack("audio");
Steve Antonba42e992018-04-09 14:10:01 -07001565
1566 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1567
1568 RTCError error;
1569 ASSERT_FALSE(caller->SetRemoteDescription(callee->CreateAnswer(), &error));
1570 EXPECT_EQ(RTCErrorType::INVALID_STATE, error.type());
1571}
1572
1573// Test that a Unified Plan PeerConnection fails to set a Plan B offer if it has
1574// two video tracks.
1575TEST_F(PeerConnectionJsepTest, TwoVideoPlanBToUnifiedPlanFails) {
1576 RTCConfiguration config_planb;
1577 config_planb.sdp_semantics = SdpSemantics::kPlanB;
1578 auto caller = CreatePeerConnection(config_planb);
1579 auto callee = CreatePeerConnection();
1580 caller->AddVideoTrack("video1");
1581 caller->AddVideoTrack("video2");
1582
1583 RTCError error;
1584 ASSERT_FALSE(callee->SetRemoteDescription(caller->CreateOffer(), &error));
1585 EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, error.type());
1586}
1587
1588// Test that a Unified Plan PeerConnection fails to set a Plan B answer if it
1589// has two video tracks.
1590TEST_F(PeerConnectionJsepTest, OneVideoUnifiedPlanToTwoVideoPlanBFails) {
1591 auto caller = CreatePeerConnection();
1592 RTCConfiguration config_planb;
1593 config_planb.sdp_semantics = SdpSemantics::kPlanB;
1594 auto callee = CreatePeerConnection(config_planb);
1595 caller->AddVideoTrack("video");
1596 callee->AddVideoTrack("video1");
1597 callee->AddVideoTrack("video2");
1598
1599 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1600
1601 RTCError error;
1602 ASSERT_FALSE(caller->SetRemoteDescription(caller->CreateAnswer(), &error));
1603 EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, error.type());
Harald Alvestrand5081c0c2018-03-09 15:18:03 +01001604}
1605
Steve Anton06817cd2018-12-18 15:55:30 -08001606// Removes the RTP header extension associated with the given URI from the media
1607// description.
1608static void RemoveRtpHeaderExtensionByUri(
1609 MediaContentDescription* media_description,
1610 absl::string_view uri) {
1611 std::vector<RtpExtension> header_extensions =
1612 media_description->rtp_header_extensions();
1613 header_extensions.erase(std::remove_if(
1614 header_extensions.begin(), header_extensions.end(),
1615 [uri](const RtpExtension& extension) { return extension.uri == uri; }));
1616 media_description->set_rtp_header_extensions(header_extensions);
1617}
1618
1619// Transforms a session description to emulate a legacy endpoint which does not
1620// support a=mid, BUNDLE, and the MID header extension.
1621static void ClearMids(SessionDescriptionInterface* sdesc) {
1622 cricket::SessionDescription* desc = sdesc->description();
1623 desc->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1624 cricket::ContentInfo* audio_content = cricket::GetFirstAudioContent(desc);
1625 if (audio_content) {
1626 desc->GetTransportInfoByName(audio_content->name)->content_name = "";
1627 audio_content->name = "";
1628 RemoveRtpHeaderExtensionByUri(audio_content->media_description(),
1629 RtpExtension::kMidUri);
1630 }
1631 cricket::ContentInfo* video_content = cricket::GetFirstVideoContent(desc);
1632 if (video_content) {
1633 desc->GetTransportInfoByName(video_content->name)->content_name = "";
1634 video_content->name = "";
1635 RemoveRtpHeaderExtensionByUri(video_content->media_description(),
1636 RtpExtension::kMidUri);
1637 }
1638}
1639
1640// Test that negotiation works with legacy endpoints which do not support a=mid.
1641TEST_F(PeerConnectionJsepTest, LegacyNoMidAudioOnlyOffer) {
1642 auto caller = CreatePeerConnection();
1643 caller->AddAudioTrack("audio");
1644 auto callee = CreatePeerConnection();
1645 callee->AddAudioTrack("audio");
1646
1647 auto offer = caller->CreateOffer();
1648 ClearMids(offer.get());
1649
1650 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1651 EXPECT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1652}
1653TEST_F(PeerConnectionJsepTest, LegacyNoMidAudioVideoOffer) {
1654 auto caller = CreatePeerConnection();
1655 caller->AddAudioTrack("audio");
1656 caller->AddVideoTrack("video");
1657 auto callee = CreatePeerConnection();
1658 callee->AddAudioTrack("audio");
1659 callee->AddVideoTrack("video");
1660
1661 auto offer = caller->CreateOffer();
1662 ClearMids(offer.get());
1663
1664 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1665 EXPECT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1666}
1667TEST_F(PeerConnectionJsepTest, LegacyNoMidAudioOnlyAnswer) {
1668 auto caller = CreatePeerConnection();
1669 caller->AddAudioTrack("audio");
1670 auto callee = CreatePeerConnection();
1671 callee->AddAudioTrack("audio");
1672
1673 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1674
1675 auto answer = callee->CreateAnswer();
1676 ClearMids(answer.get());
1677
1678 EXPECT_TRUE(caller->SetRemoteDescription(std::move(answer)));
1679}
1680TEST_F(PeerConnectionJsepTest, LegacyNoMidAudioVideoAnswer) {
1681 auto caller = CreatePeerConnection();
1682 caller->AddAudioTrack("audio");
1683 caller->AddVideoTrack("video");
1684 auto callee = CreatePeerConnection();
1685 callee->AddAudioTrack("audio");
1686 callee->AddVideoTrack("video");
1687
1688 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1689
1690 auto answer = callee->CreateAnswer();
1691 ClearMids(answer.get());
1692
1693 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
1694}
1695
Steve Antond7180cc2019-02-07 10:44:53 -08001696// Test that negotiation works with legacy endpoints which do not support a=mid
1697// when setting two remote descriptions without setting a local description in
1698// between.
1699TEST_F(PeerConnectionJsepTest, LegacyNoMidTwoRemoteOffers) {
1700 auto caller = CreatePeerConnection();
1701 caller->AddAudioTrack("audio");
1702 auto callee = CreatePeerConnection();
1703 callee->AddAudioTrack("audio");
1704
1705 auto offer = caller->CreateOffer();
1706 ClearMids(offer.get());
1707
1708 ASSERT_TRUE(
1709 callee->SetRemoteDescription(CloneSessionDescription(offer.get())));
1710 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1711 EXPECT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1712}
1713
Steve Antonceac0152018-12-19 11:32:20 -08001714// Test that SetLocalDescription fails if a=mid lines are missing.
1715TEST_F(PeerConnectionJsepTest, SetLocalDescriptionFailsMissingMid) {
1716 auto caller = CreatePeerConnection();
1717 caller->AddAudioTrack("audio");
1718
1719 auto offer = caller->CreateOffer();
1720 ClearMids(offer.get());
1721
1722 std::string error;
1723 ASSERT_FALSE(caller->SetLocalDescription(std::move(offer), &error));
1724 EXPECT_EQ(
1725 "Failed to set local offer sdp: A media section is missing a MID "
1726 "attribute.",
1727 error);
1728}
1729
Eldar Rello5ab79e62019-10-09 18:29:44 +03001730TEST_F(PeerConnectionJsepTest, RollbackSupportedInUnifiedPlan) {
1731 RTCConfiguration config;
1732 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
1733 config.enable_implicit_rollback = true;
1734 auto caller = CreatePeerConnection(config);
1735 auto callee = CreatePeerConnection(config);
1736 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
1737 EXPECT_TRUE(caller->SetLocalDescription(caller->CreateRollback()));
1738 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
1739 EXPECT_TRUE(caller->SetRemoteDescription(caller->CreateRollback()));
1740 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
1741 EXPECT_TRUE(caller->SetRemoteDescription(callee->CreateOffer()));
1742}
1743
1744TEST_F(PeerConnectionJsepTest, RollbackNotSupportedInPlanB) {
1745 RTCConfiguration config;
1746 config.sdp_semantics = SdpSemantics::kPlanB;
1747 config.enable_implicit_rollback = true;
1748 auto caller = CreatePeerConnection(config);
1749 auto callee = CreatePeerConnection(config);
1750 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
1751 EXPECT_FALSE(caller->SetLocalDescription(caller->CreateRollback()));
1752 EXPECT_FALSE(caller->SetRemoteDescription(caller->CreateRollback()));
1753 EXPECT_FALSE(caller->SetRemoteDescription(callee->CreateOffer()));
1754}
1755
1756TEST_F(PeerConnectionJsepTest, RollbackFailsInStableState) {
1757 auto caller = CreatePeerConnection();
1758 EXPECT_FALSE(caller->SetLocalDescription(caller->CreateRollback()));
1759 EXPECT_FALSE(caller->SetRemoteDescription(caller->CreateRollback()));
1760}
1761
1762TEST_F(PeerConnectionJsepTest, RollbackToStableStateAndClearLocalOffer) {
1763 auto caller = CreatePeerConnection();
1764 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
1765 EXPECT_TRUE(caller->SetLocalDescription(caller->CreateRollback()));
1766 EXPECT_EQ(caller->signaling_state(), PeerConnectionInterface::kStable);
1767 EXPECT_EQ(caller->pc()->pending_local_description(), nullptr);
1768
1769 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
1770 EXPECT_TRUE(caller->SetRemoteDescription(caller->CreateRollback()));
1771 EXPECT_EQ(caller->signaling_state(), PeerConnectionInterface::kStable);
1772 EXPECT_EQ(caller->pc()->pending_local_description(), nullptr);
1773}
1774
1775TEST_F(PeerConnectionJsepTest, RollbackToStableStateAndClearRemoteOffer) {
1776 auto caller = CreatePeerConnection();
1777 auto callee = CreatePeerConnection();
1778 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1779 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
1780 EXPECT_EQ(callee->signaling_state(), PeerConnectionInterface::kStable);
1781 EXPECT_EQ(callee->pc()->pending_remote_description(), nullptr);
1782
1783 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1784 EXPECT_TRUE(callee->SetLocalDescription(caller->CreateRollback()));
1785 EXPECT_EQ(callee->signaling_state(), PeerConnectionInterface::kStable);
1786 EXPECT_EQ(callee->pc()->pending_remote_description(), nullptr);
1787}
1788
1789TEST_F(PeerConnectionJsepTest, RollbackLocalOfferImplicitly) {
1790 RTCConfiguration config;
1791 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
1792 config.enable_implicit_rollback = true;
1793 auto caller = CreatePeerConnection(config);
1794 auto callee = CreatePeerConnection(config);
1795 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
1796 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1797 EXPECT_EQ(callee->signaling_state(),
1798 PeerConnectionInterface::kHaveRemoteOffer);
1799}
1800
1801TEST_F(PeerConnectionJsepTest, AttemptToRollbackLocalOfferImplicitly) {
1802 RTCConfiguration config;
1803 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
1804 config.enable_implicit_rollback = true;
1805 auto caller = CreatePeerConnection(config);
1806 auto callee = CreatePeerConnection(config);
1807 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
1808 EXPECT_FALSE(callee->SetRemoteDescription(
1809 CreateSessionDescription(SdpType::kOffer, "invalid sdp")));
1810 EXPECT_EQ(callee->signaling_state(),
1811 PeerConnectionInterface::kHaveLocalOffer);
1812}
1813
1814TEST_F(PeerConnectionJsepTest, RollbackRemovesTransceiver) {
1815 auto caller = CreatePeerConnection();
1816 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1817 auto callee = CreatePeerConnection();
1818 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1819 EXPECT_EQ(callee->pc()->GetTransceivers().size(), size_t{1});
1820 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
1821 EXPECT_EQ(callee->pc()->GetTransceivers().size(), size_t{0});
1822}
1823
1824TEST_F(PeerConnectionJsepTest, RollbackKeepsTransceiverAndClearsMid) {
1825 auto caller = CreatePeerConnection();
1826 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1827 auto callee = CreatePeerConnection();
1828 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1829 callee->AddAudioTrack("a");
1830 EXPECT_EQ(callee->pc()->GetTransceivers().size(), size_t{1});
1831 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
1832 // Transceiver can't be removed as track was added to it.
1833 EXPECT_EQ(callee->pc()->GetTransceivers().size(), size_t{1});
1834 // Mid got cleared to make it reusable.
1835 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), absl::nullopt);
1836 // Transceiver should be counted as addTrack-created after rollback.
1837 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1838 EXPECT_EQ(callee->pc()->GetTransceivers().size(), size_t{1});
1839}
1840
1841TEST_F(PeerConnectionJsepTest, RollbackRestoresMid) {
1842 auto caller = CreatePeerConnection();
1843 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1844 auto callee = CreatePeerConnection();
1845 callee->AddAudioTrack("a");
1846 auto offer = callee->CreateOffer();
1847 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1848 EXPECT_EQ(callee->pc()->GetTransceivers().size(), size_t{1});
1849 EXPECT_NE(callee->pc()->GetTransceivers()[0]->mid(), absl::nullopt);
1850 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
1851 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), absl::nullopt);
1852 EXPECT_TRUE(callee->SetLocalDescription(std::move(offer)));
1853}
1854
1855TEST_F(PeerConnectionJsepTest, RollbackRestoresMidAndRemovesTransceiver) {
1856 auto callee = CreatePeerConnection();
1857 callee->AddVideoTrack("a");
1858 auto offer = callee->CreateOffer();
1859 auto caller = CreatePeerConnection();
1860 caller->AddAudioTrack("b");
1861 caller->AddVideoTrack("c");
1862 auto mid = callee->pc()->GetTransceivers()[0]->mid();
1863 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1864 EXPECT_EQ(callee->pc()->GetTransceivers().size(), size_t{2});
1865 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
1866 EXPECT_EQ(callee->pc()->GetTransceivers().size(), size_t{1});
1867 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), mid);
1868 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->media_type(),
1869 cricket::MEDIA_TYPE_VIDEO);
1870 EXPECT_TRUE(callee->SetLocalDescription(std::move(offer)));
1871}
1872
1873TEST_F(PeerConnectionJsepTest, ImplicitlyRollbackTransceiversWithSameMids) {
1874 RTCConfiguration config;
1875 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
1876 config.enable_implicit_rollback = true;
1877 auto caller = CreatePeerConnection(config);
1878 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
1879 auto callee = CreatePeerConnection(config);
1880 callee->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
1881 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
1882 auto initial_mid = callee->pc()->GetTransceivers()[0]->mid();
1883 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1884 EXPECT_EQ(callee->pc()->GetTransceivers().size(), size_t{2});
1885 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), absl::nullopt);
1886 EXPECT_EQ(callee->pc()->GetTransceivers()[1]->mid(),
1887 caller->pc()->GetTransceivers()[0]->mid());
1888 EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal()); // Go to stable.
1889 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
1890 EXPECT_NE(callee->pc()->GetTransceivers()[0]->mid(), initial_mid);
1891}
1892
1893TEST_F(PeerConnectionJsepTest, RollbackToNegotiatedStableState) {
1894 RTCConfiguration config;
1895 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
1896 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
1897 auto caller = CreatePeerConnection(config);
1898 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1899 auto callee = CreatePeerConnection(config);
1900 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1901 EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal());
1902 caller->AddVideoTrack("a");
1903 callee->AddVideoTrack("b");
1904 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
1905 EXPECT_EQ(callee->pc()->GetTransceivers().size(), size_t{2});
1906 auto audio_transport =
1907 callee->pc()->GetTransceivers()[0]->sender()->dtls_transport();
1908 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
1909 callee->pc()->GetTransceivers()[1]->sender()->dtls_transport());
1910 EXPECT_NE(callee->pc()->GetTransceivers()[1]->sender()->dtls_transport(),
1911 nullptr);
1912 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
1913 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
1914 audio_transport); // Audio must remain working after rollback.
1915 EXPECT_EQ(callee->pc()->GetTransceivers()[1]->sender()->dtls_transport(),
1916 nullptr);
1917 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1918
1919 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
1920 audio_transport); // Audio transport is still the same.
1921}
1922
1923TEST_F(PeerConnectionJsepTest, RollbackAfterMultipleSLD) {
1924 auto callee = CreatePeerConnection();
1925 callee->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1926 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
1927 callee->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
1928 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
1929 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
1930 EXPECT_EQ(callee->pc()->GetTransceivers().size(), size_t{2});
1931 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), absl::nullopt);
1932 EXPECT_EQ(callee->pc()->GetTransceivers()[1]->mid(), absl::nullopt);
1933}
1934
1935TEST_F(PeerConnectionJsepTest, NoRollbackNeeded) {
1936 auto caller = CreatePeerConnection();
1937 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1938 auto callee = CreatePeerConnection();
1939 callee->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1940 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
1941 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
1942 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1943 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1944}
1945
Steve Antondcc3c022017-12-22 16:02:54 -08001946} // namespace webrtc