blob: ba51214ac3d5a89bbf9b60a81fd87a008dde4185 [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"
Erik Språngceb44952020-09-22 11:36:35 +020014#include "api/transport/field_trial_based_config.h"
Steve Anton10542f22019-01-11 09:11:00 -080015#include "media/engine/webrtc_media_engine.h"
Danil Chapovalov9da25bd2019-06-20 10:19:42 +020016#include "media/engine/webrtc_media_engine_defaults.h"
Steve Anton10542f22019-01-11 09:11:00 -080017#include "pc/media_session.h"
18#include "pc/peer_connection_factory.h"
19#include "pc/peer_connection_wrapper.h"
20#include "pc/sdp_utils.h"
Steve Antondcc3c022017-12-22 16:02:54 -080021#ifdef WEBRTC_ANDROID
Steve Anton10542f22019-01-11 09:11:00 -080022#include "pc/test/android_test_initializer.h"
Steve Antondcc3c022017-12-22 16:02:54 -080023#endif
Steve Anton10542f22019-01-11 09:11:00 -080024#include "pc/test/fake_audio_capture_module.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"
Per Kjellander2bca0082020-08-28 09:15:15 +020028#include "test/pc/sctp/fake_sctp_transport.h"
Steve Antondcc3c022017-12-22 16:02:54 -080029
30// This file contains tests that ensure the PeerConnection's implementation of
31// CreateOffer/CreateAnswer/SetLocalDescription/SetRemoteDescription conform
32// to the JavaScript Session Establishment Protocol (JSEP).
33// For now these semantics are only available when configuring the
34// PeerConnection with Unified Plan, but eventually that will be the default.
35
36namespace webrtc {
37
38using cricket::MediaContentDescription;
39using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
Steve Antondcc3c022017-12-22 16:02:54 -080040using ::testing::Combine;
41using ::testing::ElementsAre;
Steve Antonef65ef12018-01-10 17:15:20 -080042using ::testing::UnorderedElementsAre;
Jonas Olssona4d87372019-07-05 19:08:33 +020043using ::testing::Values;
Steve Antondcc3c022017-12-22 16:02:54 -080044
Per Kjellander2bca0082020-08-28 09:15:15 +020045PeerConnectionFactoryDependencies CreatePeerConnectionFactoryDependencies() {
46 PeerConnectionFactoryDependencies dependencies;
47 dependencies.worker_thread = rtc::Thread::Current();
48 dependencies.network_thread = rtc::Thread::Current();
49 dependencies.signaling_thread = rtc::Thread::Current();
50 dependencies.task_queue_factory = CreateDefaultTaskQueueFactory();
Erik Språngceb44952020-09-22 11:36:35 +020051 dependencies.trials = std::make_unique<FieldTrialBasedConfig>();
Per Kjellander2bca0082020-08-28 09:15:15 +020052 cricket::MediaEngineDependencies media_deps;
53 media_deps.task_queue_factory = dependencies.task_queue_factory.get();
54 media_deps.adm = FakeAudioCaptureModule::Create();
Erik Språngceb44952020-09-22 11:36:35 +020055 media_deps.trials = dependencies.trials.get();
Per Kjellander2bca0082020-08-28 09:15:15 +020056 SetMediaEngineDefaults(&media_deps);
57 dependencies.media_engine = cricket::CreateMediaEngine(std::move(media_deps));
58 dependencies.call_factory = CreateCallFactory();
59 dependencies.sctp_factory = std::make_unique<FakeSctpTransportFactory>();
60 return dependencies;
61}
Steve Antonfa2260d2017-12-28 16:38:23 -080062
Steve Antondcc3c022017-12-22 16:02:54 -080063class PeerConnectionJsepTest : public ::testing::Test {
64 protected:
65 typedef std::unique_ptr<PeerConnectionWrapper> WrapperPtr;
66
67 PeerConnectionJsepTest()
68 : vss_(new rtc::VirtualSocketServer()), main_(vss_.get()) {
69#ifdef WEBRTC_ANDROID
70 InitializeAndroidObjects();
71#endif
Steve Antondcc3c022017-12-22 16:02:54 -080072 }
73
74 WrapperPtr CreatePeerConnection() {
75 RTCConfiguration config;
76 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
77 return CreatePeerConnection(config);
78 }
79
80 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
Per Kjellander2bca0082020-08-28 09:15:15 +020081 rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory =
82 CreateModularPeerConnectionFactory(
83 CreatePeerConnectionFactoryDependencies());
Mirko Bonadei317a1f02019-09-17 17:06:18 +020084 auto observer = std::make_unique<MockPeerConnectionObserver>();
Steve Antonfa2260d2017-12-28 16:38:23 -080085 auto pc = pc_factory->CreatePeerConnection(config, nullptr, nullptr,
86 observer.get());
Steve Antondcc3c022017-12-22 16:02:54 -080087 if (!pc) {
88 return nullptr;
89 }
90
Yves Gerey4e933292018-10-31 15:36:05 +010091 observer->SetPeerConnectionInterface(pc.get());
Mirko Bonadei317a1f02019-09-17 17:06:18 +020092 return std::make_unique<PeerConnectionWrapper>(pc_factory, pc,
93 std::move(observer));
Steve Antondcc3c022017-12-22 16:02:54 -080094 }
95
96 std::unique_ptr<rtc::VirtualSocketServer> vss_;
97 rtc::AutoSocketServerThread main_;
Steve Antondcc3c022017-12-22 16:02:54 -080098};
99
100// Tests for JSEP initial offer generation.
101
102// Test that an offer created by a PeerConnection with no transceivers generates
103// no media sections.
104TEST_F(PeerConnectionJsepTest, EmptyInitialOffer) {
105 auto caller = CreatePeerConnection();
Steve Antonfa2260d2017-12-28 16:38:23 -0800106
Steve Antondcc3c022017-12-22 16:02:54 -0800107 auto offer = caller->CreateOffer();
Steve Antonfa2260d2017-12-28 16:38:23 -0800108 ASSERT_EQ(0u, offer->description()->contents().size());
Steve Antondcc3c022017-12-22 16:02:54 -0800109}
110
111// Test that an initial offer with one audio track generates one audio media
112// section.
113TEST_F(PeerConnectionJsepTest, AudioOnlyInitialOffer) {
114 auto caller = CreatePeerConnection();
115 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
Steve Antondcc3c022017-12-22 16:02:54 -0800116
Steve Antonfa2260d2017-12-28 16:38:23 -0800117 auto offer = caller->CreateOffer();
Steve Antondcc3c022017-12-22 16:02:54 -0800118 auto contents = offer->description()->contents();
119 ASSERT_EQ(1u, contents.size());
120 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, contents[0].media_description()->type());
121}
122
123// Test than an initial offer with one video track generates one video media
124// section
125TEST_F(PeerConnectionJsepTest, VideoOnlyInitialOffer) {
126 auto caller = CreatePeerConnection();
127 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
Steve Antondcc3c022017-12-22 16:02:54 -0800128
Steve Antonfa2260d2017-12-28 16:38:23 -0800129 auto offer = caller->CreateOffer();
Steve Antondcc3c022017-12-22 16:02:54 -0800130 auto contents = offer->description()->contents();
131 ASSERT_EQ(1u, contents.size());
132 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, contents[0].media_description()->type());
133}
134
Steve Antonfa2260d2017-12-28 16:38:23 -0800135// Test that an initial offer with one data channel generates one data media
136// section.
137TEST_F(PeerConnectionJsepTest, DataOnlyInitialOffer) {
138 auto caller = CreatePeerConnection();
139 caller->CreateDataChannel("dc");
140
141 auto offer = caller->CreateOffer();
142 auto contents = offer->description()->contents();
143 ASSERT_EQ(1u, contents.size());
144 EXPECT_EQ(cricket::MEDIA_TYPE_DATA, contents[0].media_description()->type());
145}
146
147// Test that creating multiple data channels only results in one data section
148// generated in the offer.
149TEST_F(PeerConnectionJsepTest, MultipleDataChannelsCreateOnlyOneDataSection) {
150 auto caller = CreatePeerConnection();
151 caller->CreateDataChannel("first");
152 caller->CreateDataChannel("second");
153 caller->CreateDataChannel("third");
154
155 auto offer = caller->CreateOffer();
156 ASSERT_EQ(1u, offer->description()->contents().size());
157}
158
Steve Antondcc3c022017-12-22 16:02:54 -0800159// Test that multiple media sections in the initial offer are ordered in the
160// order the transceivers were added to the PeerConnection. This is required by
161// JSEP section 5.2.1.
162TEST_F(PeerConnectionJsepTest, MediaSectionsInInitialOfferOrderedCorrectly) {
163 auto caller = CreatePeerConnection();
164 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
165 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
166 RtpTransceiverInit init;
167 init.direction = RtpTransceiverDirection::kSendOnly;
168 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init);
Steve Antondcc3c022017-12-22 16:02:54 -0800169
Steve Antonfa2260d2017-12-28 16:38:23 -0800170 auto offer = caller->CreateOffer();
Steve Antondcc3c022017-12-22 16:02:54 -0800171 auto contents = offer->description()->contents();
172 ASSERT_EQ(3u, contents.size());
173
174 const MediaContentDescription* media_description1 =
175 contents[0].media_description();
176 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, media_description1->type());
177 EXPECT_EQ(RtpTransceiverDirection::kSendRecv,
178 media_description1->direction());
179
180 const MediaContentDescription* media_description2 =
181 contents[1].media_description();
182 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, media_description2->type());
183 EXPECT_EQ(RtpTransceiverDirection::kSendRecv,
184 media_description2->direction());
185
186 const MediaContentDescription* media_description3 =
187 contents[2].media_description();
188 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, media_description3->type());
189 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
190 media_description3->direction());
191}
192
193// Test that media sections in the initial offer have different mids.
194TEST_F(PeerConnectionJsepTest, MediaSectionsInInitialOfferHaveDifferentMids) {
195 auto caller = CreatePeerConnection();
196 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
197 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
Steve Antonfa2260d2017-12-28 16:38:23 -0800198
Steve Antondcc3c022017-12-22 16:02:54 -0800199 auto offer = caller->CreateOffer();
Steve Antondcc3c022017-12-22 16:02:54 -0800200 auto contents = offer->description()->contents();
201 ASSERT_EQ(2u, contents.size());
202 EXPECT_NE(contents[0].name, contents[1].name);
203}
204
205TEST_F(PeerConnectionJsepTest,
206 StoppedTransceiverHasNoMediaSectionInInitialOffer) {
207 auto caller = CreatePeerConnection();
208 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
Harald Alvestrand6060df52020-08-11 09:54:02 +0200209 transceiver->StopInternal();
Steve Antondcc3c022017-12-22 16:02:54 -0800210
211 auto offer = caller->CreateOffer();
212 EXPECT_EQ(0u, offer->description()->contents().size());
213}
214
215// Tests for JSEP SetLocalDescription with a local offer.
216
217TEST_F(PeerConnectionJsepTest, SetLocalEmptyOfferCreatesNoTransceivers) {
218 auto caller = CreatePeerConnection();
Steve Antonfa2260d2017-12-28 16:38:23 -0800219
Steve Antondcc3c022017-12-22 16:02:54 -0800220 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
221
222 EXPECT_THAT(caller->pc()->GetTransceivers(), ElementsAre());
223 EXPECT_THAT(caller->pc()->GetSenders(), ElementsAre());
224 EXPECT_THAT(caller->pc()->GetReceivers(), ElementsAre());
225}
226
227TEST_F(PeerConnectionJsepTest, SetLocalOfferSetsTransceiverMid) {
228 auto caller = CreatePeerConnection();
229 auto audio_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
230 auto video_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
231
232 auto offer = caller->CreateOffer();
233 std::string audio_mid = offer->description()->contents()[0].name;
234 std::string video_mid = offer->description()->contents()[1].name;
235
236 ASSERT_TRUE(caller->SetLocalDescription(std::move(offer)));
237
238 EXPECT_EQ(audio_mid, audio_transceiver->mid());
239 EXPECT_EQ(video_mid, video_transceiver->mid());
240}
241
242// Tests for JSEP SetRemoteDescription with a remote offer.
243
244// Test that setting a remote offer with sendrecv audio and video creates two
245// transceivers, one for receiving audio and one for receiving video.
246TEST_F(PeerConnectionJsepTest, SetRemoteOfferCreatesTransceivers) {
247 auto caller = CreatePeerConnection();
248 auto caller_audio = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
249 auto caller_video = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
250 auto callee = CreatePeerConnection();
251
252 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
253
254 auto transceivers = callee->pc()->GetTransceivers();
255 ASSERT_EQ(2u, transceivers.size());
Steve Anton1bc97162018-06-25 14:04:01 -0700256
Steve Anton69470252018-02-09 11:43:08 -0800257 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, transceivers[0]->media_type());
Steve Antondcc3c022017-12-22 16:02:54 -0800258 EXPECT_EQ(caller_audio->mid(), transceivers[0]->mid());
259 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly, transceivers[0]->direction());
Steve Anton1bc97162018-06-25 14:04:01 -0700260 EXPECT_EQ(0u, transceivers[0]->sender()->stream_ids().size());
261
Steve Anton69470252018-02-09 11:43:08 -0800262 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, transceivers[1]->media_type());
Steve Antondcc3c022017-12-22 16:02:54 -0800263 EXPECT_EQ(caller_video->mid(), transceivers[1]->mid());
264 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly, transceivers[1]->direction());
Steve Anton1bc97162018-06-25 14:04:01 -0700265 EXPECT_EQ(0u, transceivers[1]->sender()->stream_ids().size());
Steve Antondcc3c022017-12-22 16:02:54 -0800266}
267
268// Test that setting a remote offer with an audio track will reuse the
269// transceiver created for a local audio track added by AddTrack.
270// This is specified in JSEP section 5.10 (Applying a Remote Description). The
271// intent is to preserve backwards compatibility with clients who only use the
272// AddTrack API.
273TEST_F(PeerConnectionJsepTest, SetRemoteOfferReusesTransceiverFromAddTrack) {
274 auto caller = CreatePeerConnection();
275 caller->AddAudioTrack("a");
276 auto caller_audio = caller->pc()->GetTransceivers()[0];
277 auto callee = CreatePeerConnection();
278 callee->AddAudioTrack("a");
279
280 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
281
282 auto transceivers = callee->pc()->GetTransceivers();
283 ASSERT_EQ(1u, transceivers.size());
284 EXPECT_EQ(MediaStreamTrackInterface::kAudioKind,
285 transceivers[0]->receiver()->track()->kind());
286 EXPECT_EQ(caller_audio->mid(), transceivers[0]->mid());
287}
288
289// Test that setting a remote offer with an audio track marked sendonly will not
290// reuse a transceiver created by AddTrack. JSEP only allows the transceiver to
291// be reused if the offer direction is sendrecv or recvonly.
292TEST_F(PeerConnectionJsepTest,
293 SetRemoteOfferDoesNotReuseTransceiverIfDirectionSendOnly) {
294 auto caller = CreatePeerConnection();
295 caller->AddAudioTrack("a");
296 auto caller_audio = caller->pc()->GetTransceivers()[0];
Harald Alvestrand6060df52020-08-11 09:54:02 +0200297 caller_audio->SetDirectionWithError(RtpTransceiverDirection::kSendOnly);
Steve Antondcc3c022017-12-22 16:02:54 -0800298 auto callee = CreatePeerConnection();
299 callee->AddAudioTrack("a");
300
301 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
302
303 auto transceivers = callee->pc()->GetTransceivers();
304 ASSERT_EQ(2u, transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200305 EXPECT_EQ(absl::nullopt, transceivers[0]->mid());
Steve Antondcc3c022017-12-22 16:02:54 -0800306 EXPECT_EQ(caller_audio->mid(), transceivers[1]->mid());
307}
308
309// Test that setting a remote offer with an audio track will not reuse a
310// transceiver added by AddTransceiver. The logic for reusing a transceiver is
311// specific to those added by AddTrack and is tested above.
312TEST_F(PeerConnectionJsepTest,
313 SetRemoteOfferDoesNotReuseTransceiverFromAddTransceiver) {
314 auto caller = CreatePeerConnection();
315 caller->AddAudioTrack("a");
316 auto callee = CreatePeerConnection();
317 auto transceiver = callee->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
318
319 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
320
321 auto transceivers = callee->pc()->GetTransceivers();
322 ASSERT_EQ(2u, transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200323 EXPECT_EQ(absl::nullopt, transceivers[0]->mid());
Steve Antondcc3c022017-12-22 16:02:54 -0800324 EXPECT_EQ(caller->pc()->GetTransceivers()[0]->mid(), transceivers[1]->mid());
325 EXPECT_EQ(MediaStreamTrackInterface::kAudioKind,
326 transceivers[1]->receiver()->track()->kind());
327}
328
329// Test that setting a remote offer with an audio track will not reuse a
330// transceiver created for a local video track added by AddTrack.
331TEST_F(PeerConnectionJsepTest,
332 SetRemoteOfferDoesNotReuseTransceiverOfWrongType) {
333 auto caller = CreatePeerConnection();
334 caller->AddAudioTrack("a");
335 auto callee = CreatePeerConnection();
336 auto video_sender = callee->AddVideoTrack("v");
337
338 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
339
340 auto transceivers = callee->pc()->GetTransceivers();
341 ASSERT_EQ(2u, transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200342 EXPECT_EQ(absl::nullopt, transceivers[0]->mid());
Steve Antondcc3c022017-12-22 16:02:54 -0800343 EXPECT_EQ(caller->pc()->GetTransceivers()[0]->mid(), transceivers[1]->mid());
344 EXPECT_EQ(MediaStreamTrackInterface::kAudioKind,
345 transceivers[1]->receiver()->track()->kind());
346}
347
348// Test that setting a remote offer with an audio track will not reuse a
349// stopped transceiver.
350TEST_F(PeerConnectionJsepTest, SetRemoteOfferDoesNotReuseStoppedTransceiver) {
351 auto caller = CreatePeerConnection();
352 caller->AddAudioTrack("a");
353 auto callee = CreatePeerConnection();
354 callee->AddAudioTrack("a");
Harald Alvestrand6060df52020-08-11 09:54:02 +0200355 callee->pc()->GetTransceivers()[0]->StopInternal();
Steve Antondcc3c022017-12-22 16:02:54 -0800356
357 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
358
359 auto transceivers = callee->pc()->GetTransceivers();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200360 ASSERT_EQ(1u, transceivers.size());
361 EXPECT_EQ(caller->pc()->GetTransceivers()[0]->mid(), transceivers[0]->mid());
362 EXPECT_FALSE(transceivers[0]->stopped());
Steve Antondcc3c022017-12-22 16:02:54 -0800363}
364
365// Test that audio and video transceivers created on the remote side with
366// AddTrack will all be reused if there is the same number of audio/video tracks
367// in the remote offer. Additionally, this tests that transceivers are
368// successfully matched even if they are in a different order on the remote
369// side.
370TEST_F(PeerConnectionJsepTest, SetRemoteOfferReusesTransceiversOfBothTypes) {
371 auto caller = CreatePeerConnection();
372 caller->AddVideoTrack("v");
373 caller->AddAudioTrack("a");
374 auto callee = CreatePeerConnection();
375 callee->AddAudioTrack("a");
376 callee->AddVideoTrack("v");
377
378 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
379
380 auto caller_transceivers = caller->pc()->GetTransceivers();
381 auto callee_transceivers = callee->pc()->GetTransceivers();
382 ASSERT_EQ(2u, callee_transceivers.size());
383 EXPECT_EQ(caller_transceivers[0]->mid(), callee_transceivers[1]->mid());
384 EXPECT_EQ(caller_transceivers[1]->mid(), callee_transceivers[0]->mid());
385}
386
387// Tests for JSEP initial CreateAnswer.
388
389// Test that the answer to a remote offer creates media sections for each
390// offered media in the same order and with the same mids.
391TEST_F(PeerConnectionJsepTest, CreateAnswerHasSameMidsAsOffer) {
392 auto caller = CreatePeerConnection();
393 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
394 auto second_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
395 auto third_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
Steve Antonfa2260d2017-12-28 16:38:23 -0800396 caller->CreateDataChannel("dc");
Steve Antondcc3c022017-12-22 16:02:54 -0800397 auto callee = CreatePeerConnection();
398
Steve Antonfa2260d2017-12-28 16:38:23 -0800399 auto offer = caller->CreateOffer();
400 const auto* offer_data = cricket::GetFirstDataContent(offer->description());
401 ASSERT_TRUE(
402 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
403 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
Steve Antondcc3c022017-12-22 16:02:54 -0800404
405 auto answer = callee->CreateAnswer();
406 auto contents = answer->description()->contents();
Steve Antonfa2260d2017-12-28 16:38:23 -0800407 ASSERT_EQ(4u, contents.size());
Steve Antondcc3c022017-12-22 16:02:54 -0800408 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, contents[0].media_description()->type());
Steve Antonfa2260d2017-12-28 16:38:23 -0800409 EXPECT_EQ(first_transceiver->mid(), contents[0].name);
Steve Antondcc3c022017-12-22 16:02:54 -0800410 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, contents[1].media_description()->type());
Steve Antonfa2260d2017-12-28 16:38:23 -0800411 EXPECT_EQ(second_transceiver->mid(), contents[1].name);
Steve Antondcc3c022017-12-22 16:02:54 -0800412 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, contents[2].media_description()->type());
Steve Antonfa2260d2017-12-28 16:38:23 -0800413 EXPECT_EQ(third_transceiver->mid(), contents[2].name);
414 EXPECT_EQ(cricket::MEDIA_TYPE_DATA, contents[3].media_description()->type());
415 EXPECT_EQ(offer_data->name, contents[3].name);
Steve Antondcc3c022017-12-22 16:02:54 -0800416}
417
418// Test that an answering media section is marked as rejected if the underlying
419// transceiver has been stopped.
420TEST_F(PeerConnectionJsepTest, CreateAnswerRejectsStoppedTransceiver) {
421 auto caller = CreatePeerConnection();
422 caller->AddAudioTrack("a");
423 auto callee = CreatePeerConnection();
424
425 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
426
Harald Alvestrand6060df52020-08-11 09:54:02 +0200427 callee->pc()->GetTransceivers()[0]->StopInternal();
Steve Antondcc3c022017-12-22 16:02:54 -0800428
429 auto answer = callee->CreateAnswer();
430 auto contents = answer->description()->contents();
431 ASSERT_EQ(1u, contents.size());
432 EXPECT_TRUE(contents[0].rejected);
433}
434
435// Test that CreateAnswer will generate media sections which will only send or
436// receive if the offer indicates it can do the reciprocating direction.
437// The full matrix is tested more extensively in MediaSession.
438TEST_F(PeerConnectionJsepTest, CreateAnswerNegotiatesDirection) {
439 auto caller = CreatePeerConnection();
440 RtpTransceiverInit init;
441 init.direction = RtpTransceiverDirection::kSendOnly;
442 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init);
443 auto callee = CreatePeerConnection();
444 callee->AddAudioTrack("a");
445
446 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
447
448 auto answer = callee->CreateAnswer();
449 auto contents = answer->description()->contents();
450 ASSERT_EQ(1u, contents.size());
451 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
452 contents[0].media_description()->direction());
453}
454
455// Tests for JSEP SetLocalDescription with a local answer.
456// Note that these test only the additional behaviors not covered by
457// SetLocalDescription with a local offer.
458
459// Test that SetLocalDescription with an answer sets the current_direction
460// property of the transceivers mentioned in the session description.
461TEST_F(PeerConnectionJsepTest, SetLocalAnswerUpdatesCurrentDirection) {
462 auto caller = CreatePeerConnection();
463 auto caller_audio = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
Harald Alvestrand6060df52020-08-11 09:54:02 +0200464 caller_audio->SetDirectionWithError(RtpTransceiverDirection::kRecvOnly);
Steve Antondcc3c022017-12-22 16:02:54 -0800465 auto callee = CreatePeerConnection();
466 callee->AddAudioTrack("a");
467
468 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
469 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
470
471 auto transceivers = callee->pc()->GetTransceivers();
472 ASSERT_EQ(1u, transceivers.size());
473 // Since the offer was recvonly and the transceiver direction is sendrecv,
474 // the negotiated direction will be sendonly.
475 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
476 transceivers[0]->current_direction());
477}
478
479// Tests for JSEP SetRemoteDescription with a remote answer.
480// Note that these test only the additional behaviors not covered by
481// SetRemoteDescription with a remote offer.
482
483TEST_F(PeerConnectionJsepTest, SetRemoteAnswerUpdatesCurrentDirection) {
484 auto caller = CreatePeerConnection();
485 caller->AddAudioTrack("a");
486 auto callee = CreatePeerConnection();
487 callee->AddAudioTrack("a");
488 auto callee_audio = callee->pc()->GetTransceivers()[0];
Harald Alvestrand6060df52020-08-11 09:54:02 +0200489 callee_audio->SetDirectionWithError(RtpTransceiverDirection::kSendOnly);
Steve Antondcc3c022017-12-22 16:02:54 -0800490
491 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
492 ASSERT_TRUE(
493 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
494
495 auto transceivers = caller->pc()->GetTransceivers();
496 ASSERT_EQ(1u, transceivers.size());
497 // Since the remote transceiver was set to sendonly, the negotiated direction
498 // in the answer would be sendonly which we apply as recvonly to the local
499 // transceiver.
500 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
501 transceivers[0]->current_direction());
502}
503
504// Tests for multiple round trips.
505
506// Test that setting a transceiver with the inactive direction does not stop it
507// on either the caller or the callee.
508TEST_F(PeerConnectionJsepTest, SettingTransceiverInactiveDoesNotStopIt) {
509 auto caller = CreatePeerConnection();
510 caller->AddAudioTrack("a");
511 auto callee = CreatePeerConnection();
512 callee->AddAudioTrack("a");
Harald Alvestrand6060df52020-08-11 09:54:02 +0200513 callee->pc()->GetTransceivers()[0]->SetDirectionWithError(
Steve Antondcc3c022017-12-22 16:02:54 -0800514 RtpTransceiverDirection::kInactive);
515
516 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
517 ASSERT_TRUE(
518 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
519
520 EXPECT_FALSE(caller->pc()->GetTransceivers()[0]->stopped());
521 EXPECT_FALSE(callee->pc()->GetTransceivers()[0]->stopped());
522}
523
524// Test that if a transceiver had been associated and later stopped, then a
525// media section is still generated for it and the media section is marked as
526// rejected.
527TEST_F(PeerConnectionJsepTest,
528 ReOfferMediaSectionForAssociatedStoppedTransceiverIsRejected) {
529 auto caller = CreatePeerConnection();
530 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
531 auto callee = CreatePeerConnection();
532
533 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
534 ASSERT_TRUE(
535 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
536
537 ASSERT_TRUE(transceiver->mid());
Harald Alvestrand6060df52020-08-11 09:54:02 +0200538 transceiver->StopInternal();
Steve Antondcc3c022017-12-22 16:02:54 -0800539
540 auto reoffer = caller->CreateOffer();
541 auto contents = reoffer->description()->contents();
542 ASSERT_EQ(1u, contents.size());
543 EXPECT_TRUE(contents[0].rejected);
544}
545
546// Test that stopping an associated transceiver on the caller side will stop the
547// corresponding transceiver on the remote side when the remote offer is
548// applied.
549TEST_F(PeerConnectionJsepTest,
550 StoppingTransceiverInOfferStopsTransceiverOnRemoteSide) {
551 auto caller = CreatePeerConnection();
552 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
553 auto callee = CreatePeerConnection();
554
555 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
556 ASSERT_TRUE(
557 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
558
Harald Alvestrand6060df52020-08-11 09:54:02 +0200559 transceiver->StopInternal();
Steve Antondcc3c022017-12-22 16:02:54 -0800560
561 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
562
563 auto transceivers = callee->pc()->GetTransceivers();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200564 EXPECT_EQ(0u, transceivers.size());
Steve Antondcc3c022017-12-22 16:02:54 -0800565}
566
567// Test that CreateOffer will only generate a recycled media section if the
568// transceiver to be recycled has been seen stopped by the other side first.
569TEST_F(PeerConnectionJsepTest,
570 CreateOfferDoesNotRecycleMediaSectionIfFirstStopped) {
571 auto caller = CreatePeerConnection();
572 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
573 auto callee = CreatePeerConnection();
574
575 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
576 ASSERT_TRUE(
577 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
578
579 auto second_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
Harald Alvestrand6060df52020-08-11 09:54:02 +0200580 first_transceiver->StopInternal();
Steve Antondcc3c022017-12-22 16:02:54 -0800581
582 auto reoffer = caller->CreateOffer();
583 auto contents = reoffer->description()->contents();
584 ASSERT_EQ(2u, contents.size());
585 EXPECT_TRUE(contents[0].rejected);
586 EXPECT_FALSE(contents[1].rejected);
587}
588
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800589// Test that the offer/answer and the transceivers are correctly generated and
590// updated when the media section is recycled after the callee stops a
591// transceiver and sends an answer with a 0 port.
592TEST_F(PeerConnectionJsepTest,
593 RecycleMediaSectionWhenStoppingTransceiverOnAnswerer) {
594 auto caller = CreatePeerConnection();
595 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
596 auto callee = CreatePeerConnection();
597
598 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
Harald Alvestrand6060df52020-08-11 09:54:02 +0200599 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
600 callee->pc()->GetTransceivers()[0]->StopInternal();
Harald Alvestrandc253cb82020-09-22 21:06:05 +0000601 ASSERT_EQ(0u, callee->pc()->GetTransceivers().size());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800602 ASSERT_TRUE(
603 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
604 EXPECT_TRUE(first_transceiver->stopped());
Harald Alvestrandc253cb82020-09-22 21:06:05 +0000605 // First transceivers aren't dissociated yet on caller side.
606 ASSERT_NE(absl::nullopt, first_transceiver->mid());
607 std::string first_mid = *first_transceiver->mid();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200608 // They are disassociated on callee side.
609 ASSERT_EQ(0u, callee->pc()->GetTransceivers().size());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800610
611 // New offer exchange with new transceivers that recycles the m section
612 // correctly.
613 caller->AddAudioTrack("audio2");
614 callee->AddAudioTrack("audio2");
615 auto offer = caller->CreateOffer();
616 auto offer_contents = offer->description()->contents();
617 std::string second_mid = offer_contents[0].name;
618 ASSERT_EQ(1u, offer_contents.size());
619 EXPECT_FALSE(offer_contents[0].rejected);
620 EXPECT_NE(first_mid, second_mid);
621
622 // Setting the offer on each side will dissociate the first transceivers and
623 // associate the new transceivers.
624 ASSERT_TRUE(
625 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200626 EXPECT_EQ(absl::nullopt, first_transceiver->mid());
Harald Alvestrand6060df52020-08-11 09:54:02 +0200627 ASSERT_EQ(1u, caller->pc()->GetTransceivers().size());
628 EXPECT_EQ(second_mid, caller->pc()->GetTransceivers()[0]->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800629 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
Harald Alvestrand6060df52020-08-11 09:54:02 +0200630 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
631 EXPECT_EQ(second_mid, callee->pc()->GetTransceivers()[0]->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800632
633 // The new answer should also recycle the m section correctly.
634 auto answer = callee->CreateAnswer();
635 auto answer_contents = answer->description()->contents();
636 ASSERT_EQ(1u, answer_contents.size());
637 EXPECT_FALSE(answer_contents[0].rejected);
638 EXPECT_EQ(second_mid, answer_contents[0].name);
639
640 // Finishing the negotiation shouldn't add or dissociate any transceivers.
641 ASSERT_TRUE(
642 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
643 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
644 auto caller_transceivers = caller->pc()->GetTransceivers();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200645 ASSERT_EQ(1u, caller_transceivers.size());
646 EXPECT_EQ(second_mid, caller_transceivers[0]->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800647 auto callee_transceivers = callee->pc()->GetTransceivers();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200648 ASSERT_EQ(1u, callee_transceivers.size());
649 EXPECT_EQ(second_mid, callee_transceivers[0]->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800650}
651
652// Test that creating/setting a local offer that recycles an m= section is
653// idempotent.
654TEST_F(PeerConnectionJsepTest, CreateOfferRecyclesWhenOfferingTwice) {
655 // Do a negotiation with a port 0 for the media section.
656 auto caller = CreatePeerConnection();
657 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
658 auto callee = CreatePeerConnection();
659 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Harald Alvestrand6060df52020-08-11 09:54:02 +0200660 first_transceiver->StopInternal();
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800661 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
662 caller->AddAudioTrack("audio2");
663
664 // Create a new offer that recycles the media section and set it as a local
665 // description.
666 auto offer = caller->CreateOffer();
667 auto offer_contents = offer->description()->contents();
668 ASSERT_EQ(1u, offer_contents.size());
669 EXPECT_FALSE(offer_contents[0].rejected);
670 ASSERT_TRUE(caller->SetLocalDescription(std::move(offer)));
Harald Alvestrand6060df52020-08-11 09:54:02 +0200671 ASSERT_EQ(1u, caller->pc()->GetTransceivers().size());
672 EXPECT_FALSE(caller->pc()->GetTransceivers()[0]->stopped());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800673 std::string second_mid = offer_contents[0].name;
674
675 // Create another new offer and set the local description again without the
676 // rest of any negotation ocurring.
677 auto second_offer = caller->CreateOffer();
678 auto second_offer_contents = second_offer->description()->contents();
679 ASSERT_EQ(1u, second_offer_contents.size());
680 EXPECT_FALSE(second_offer_contents[0].rejected);
681 // The mid shouldn't change.
682 EXPECT_EQ(second_mid, second_offer_contents[0].name);
683
684 ASSERT_TRUE(caller->SetLocalDescription(std::move(second_offer)));
685 // Make sure that the caller's transceivers are associated correctly.
686 auto caller_transceivers = caller->pc()->GetTransceivers();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200687 ASSERT_EQ(1u, caller_transceivers.size());
688 EXPECT_EQ(second_mid, caller_transceivers[0]->mid());
689 EXPECT_FALSE(caller_transceivers[0]->stopped());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800690}
691
Steve Antondcc3c022017-12-22 16:02:54 -0800692// Test that the offer/answer and transceivers for both the caller and callee
693// side are generated/updated correctly when recycling an audio/video media
694// section as a media section of either the same or opposite type.
Steve Anton5c72e712018-12-10 14:25:30 -0800695// Correct recycling works as follows:
696// - The m= section is re-offered with a new MID value and the new media type.
697// - The previously-associated transceiver is dissociated when the new offer is
698// set as a local description on the offerer or as a remote description on
699// the answerer.
700// - The new transceiver is associated with the new MID value.
Steve Antondcc3c022017-12-22 16:02:54 -0800701class RecycleMediaSectionTest
702 : public PeerConnectionJsepTest,
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200703 public ::testing::WithParamInterface<
Steve Antondcc3c022017-12-22 16:02:54 -0800704 std::tuple<cricket::MediaType, cricket::MediaType>> {
705 protected:
706 RecycleMediaSectionTest() {
707 first_type_ = std::get<0>(GetParam());
708 second_type_ = std::get<1>(GetParam());
709 }
710
711 cricket::MediaType first_type_;
712 cricket::MediaType second_type_;
713};
714
Steve Anton5c72e712018-12-10 14:25:30 -0800715// Test that recycling works properly when a new transceiver recycles an m=
716// section that was rejected in both the current local and remote descriptions.
717TEST_P(RecycleMediaSectionTest, CurrentLocalAndCurrentRemoteRejected) {
Steve Antondcc3c022017-12-22 16:02:54 -0800718 auto caller = CreatePeerConnection();
719 auto first_transceiver = caller->AddTransceiver(first_type_);
720 auto callee = CreatePeerConnection();
721
722 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
723
724 std::string first_mid = *first_transceiver->mid();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200725 first_transceiver->StopInternal();
Steve Antondcc3c022017-12-22 16:02:54 -0800726
727 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
728
729 auto second_transceiver = caller->AddTransceiver(second_type_);
730
731 // The offer should reuse the previous media section but allocate a new MID
732 // and change the media type.
733 auto offer = caller->CreateOffer();
734 auto offer_contents = offer->description()->contents();
735 ASSERT_EQ(1u, offer_contents.size());
736 EXPECT_FALSE(offer_contents[0].rejected);
737 EXPECT_EQ(second_type_, offer_contents[0].media_description()->type());
738 std::string second_mid = offer_contents[0].name;
739 EXPECT_NE(first_mid, second_mid);
740
741 // Setting the local offer will dissociate the previous transceiver and set
742 // the MID for the new transceiver.
743 ASSERT_TRUE(
744 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200745 EXPECT_EQ(absl::nullopt, first_transceiver->mid());
Steve Antondcc3c022017-12-22 16:02:54 -0800746 EXPECT_EQ(second_mid, second_transceiver->mid());
747
748 // Setting the remote offer will dissociate the previous transceiver and
749 // create a new transceiver for the media section.
750 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
751 auto callee_transceivers = callee->pc()->GetTransceivers();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200752 ASSERT_EQ(1u, callee_transceivers.size());
753 EXPECT_EQ(second_mid, callee_transceivers[0]->mid());
754 EXPECT_EQ(second_type_, callee_transceivers[0]->media_type());
Steve Antondcc3c022017-12-22 16:02:54 -0800755
756 // The answer should have only one media section for the new transceiver.
757 auto answer = callee->CreateAnswer();
758 auto answer_contents = answer->description()->contents();
759 ASSERT_EQ(1u, answer_contents.size());
760 EXPECT_FALSE(answer_contents[0].rejected);
761 EXPECT_EQ(second_mid, answer_contents[0].name);
762 EXPECT_EQ(second_type_, answer_contents[0].media_description()->type());
763
764 // Setting the local answer should succeed.
765 ASSERT_TRUE(
766 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
767
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800768 // Setting the remote answer should succeed and not create any new
769 // transceivers.
Steve Antondcc3c022017-12-22 16:02:54 -0800770 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
Harald Alvestrand6060df52020-08-11 09:54:02 +0200771 ASSERT_EQ(1u, caller->pc()->GetTransceivers().size());
772 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
Steve Antondcc3c022017-12-22 16:02:54 -0800773}
774
Steve Anton5c72e712018-12-10 14:25:30 -0800775// Test that recycling works properly when a new transceiver recycles an m=
776// section that was rejected in only the current remote description.
777TEST_P(RecycleMediaSectionTest, CurrentRemoteOnlyRejected) {
778 auto caller = CreatePeerConnection();
779 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
780 auto callee = CreatePeerConnection();
781
782 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
783
784 std::string first_mid = *caller_first_transceiver->mid();
785 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
786 auto callee_first_transceiver = callee->pc()->GetTransceivers()[0];
Harald Alvestrand6060df52020-08-11 09:54:02 +0200787 callee_first_transceiver->StopInternal();
Steve Anton5c72e712018-12-10 14:25:30 -0800788
789 // The answer will have a rejected m= section.
790 ASSERT_TRUE(
791 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
792
793 // The offer should reuse the previous media section but allocate a new MID
794 // and change the media type.
795 auto caller_second_transceiver = caller->AddTransceiver(second_type_);
796 auto offer = caller->CreateOffer();
797 const auto& offer_contents = offer->description()->contents();
798 ASSERT_EQ(1u, offer_contents.size());
799 EXPECT_FALSE(offer_contents[0].rejected);
800 EXPECT_EQ(second_type_, offer_contents[0].media_description()->type());
801 std::string second_mid = offer_contents[0].name;
802 EXPECT_NE(first_mid, second_mid);
803
804 // Setting the local offer will dissociate the previous transceiver and set
805 // the MID for the new transceiver.
806 ASSERT_TRUE(
807 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
808 EXPECT_EQ(absl::nullopt, caller_first_transceiver->mid());
809 EXPECT_EQ(second_mid, caller_second_transceiver->mid());
810
811 // Setting the remote offer will dissociate the previous transceiver and
812 // create a new transceiver for the media section.
813 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
814 auto callee_transceivers = callee->pc()->GetTransceivers();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200815 ASSERT_EQ(1u, callee_transceivers.size());
816 EXPECT_EQ(second_mid, callee_transceivers[0]->mid());
817 EXPECT_EQ(second_type_, callee_transceivers[0]->media_type());
Steve Anton5c72e712018-12-10 14:25:30 -0800818
819 // The answer should have only one media section for the new transceiver.
820 auto answer = callee->CreateAnswer();
821 auto answer_contents = answer->description()->contents();
822 ASSERT_EQ(1u, answer_contents.size());
823 EXPECT_FALSE(answer_contents[0].rejected);
824 EXPECT_EQ(second_mid, answer_contents[0].name);
825 EXPECT_EQ(second_type_, answer_contents[0].media_description()->type());
826
827 // Setting the local answer should succeed.
828 ASSERT_TRUE(
829 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
830
831 // Setting the remote answer should succeed and not create any new
832 // transceivers.
833 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
Harald Alvestrand6060df52020-08-11 09:54:02 +0200834 ASSERT_EQ(1u, caller->pc()->GetTransceivers().size());
835 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
Steve Anton5c72e712018-12-10 14:25:30 -0800836}
837
838// Test that recycling works properly when a new transceiver recycles an m=
839// section that was rejected only in the current local description.
840TEST_P(RecycleMediaSectionTest, CurrentLocalOnlyRejected) {
841 auto caller = CreatePeerConnection();
842 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
843 auto callee = CreatePeerConnection();
844
845 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
846
847 std::string first_mid = *caller_first_transceiver->mid();
848 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
849 auto callee_first_transceiver = callee->pc()->GetTransceivers()[0];
Harald Alvestrand6060df52020-08-11 09:54:02 +0200850 callee_first_transceiver->StopInternal();
Steve Anton5c72e712018-12-10 14:25:30 -0800851
852 // The answer will have a rejected m= section.
853 ASSERT_TRUE(
854 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
855
856 // The offer should reuse the previous media section but allocate a new MID
857 // and change the media type.
858 auto callee_second_transceiver = callee->AddTransceiver(second_type_);
859 auto offer = callee->CreateOffer();
860 const auto& offer_contents = offer->description()->contents();
861 ASSERT_EQ(1u, offer_contents.size());
862 EXPECT_FALSE(offer_contents[0].rejected);
863 EXPECT_EQ(second_type_, offer_contents[0].media_description()->type());
864 std::string second_mid = offer_contents[0].name;
865 EXPECT_NE(first_mid, second_mid);
866
867 // Setting the local offer will dissociate the previous transceiver and set
868 // the MID for the new transceiver.
869 ASSERT_TRUE(
870 callee->SetLocalDescription(CloneSessionDescription(offer.get())));
871 EXPECT_EQ(absl::nullopt, callee_first_transceiver->mid());
872 EXPECT_EQ(second_mid, callee_second_transceiver->mid());
873
874 // Setting the remote offer will dissociate the previous transceiver and
875 // create a new transceiver for the media section.
876 ASSERT_TRUE(caller->SetRemoteDescription(std::move(offer)));
877 auto caller_transceivers = caller->pc()->GetTransceivers();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200878 ASSERT_EQ(1u, caller_transceivers.size());
879 EXPECT_EQ(second_mid, caller_transceivers[0]->mid());
880 EXPECT_EQ(second_type_, caller_transceivers[0]->media_type());
Steve Anton5c72e712018-12-10 14:25:30 -0800881
882 // The answer should have only one media section for the new transceiver.
883 auto answer = caller->CreateAnswer();
884 auto answer_contents = answer->description()->contents();
885 ASSERT_EQ(1u, answer_contents.size());
886 EXPECT_FALSE(answer_contents[0].rejected);
887 EXPECT_EQ(second_mid, answer_contents[0].name);
888 EXPECT_EQ(second_type_, answer_contents[0].media_description()->type());
889
890 // Setting the local answer should succeed.
891 ASSERT_TRUE(
892 caller->SetLocalDescription(CloneSessionDescription(answer.get())));
893
894 // Setting the remote answer should succeed and not create any new
895 // transceivers.
896 ASSERT_TRUE(callee->SetRemoteDescription(std::move(answer)));
Harald Alvestrand6060df52020-08-11 09:54:02 +0200897 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
898 ASSERT_EQ(1u, caller->pc()->GetTransceivers().size());
Steve Anton5c72e712018-12-10 14:25:30 -0800899}
900
901// Test that a m= section is *not* recycled if the media section is only
902// rejected in the pending local description and there is no current remote
903// description.
904TEST_P(RecycleMediaSectionTest, PendingLocalRejectedAndNoRemote) {
905 auto caller = CreatePeerConnection();
906 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
907
908 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
909
910 std::string first_mid = *caller_first_transceiver->mid();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200911 caller_first_transceiver->StopInternal();
Steve Anton5c72e712018-12-10 14:25:30 -0800912
913 // The reoffer will have a rejected m= section.
914 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
915
916 auto caller_second_transceiver = caller->AddTransceiver(second_type_);
917
918 // The reoffer should not recycle the existing m= section since it is not
919 // rejected in either the *current* local or *current* remote description.
920 auto reoffer = caller->CreateOffer();
921 auto reoffer_contents = reoffer->description()->contents();
922 ASSERT_EQ(2u, reoffer_contents.size());
923 EXPECT_TRUE(reoffer_contents[0].rejected);
924 EXPECT_EQ(first_type_, reoffer_contents[0].media_description()->type());
925 EXPECT_EQ(first_mid, reoffer_contents[0].name);
926 EXPECT_FALSE(reoffer_contents[1].rejected);
927 EXPECT_EQ(second_type_, reoffer_contents[1].media_description()->type());
928 std::string second_mid = reoffer_contents[1].name;
929 EXPECT_NE(first_mid, second_mid);
930
931 ASSERT_TRUE(caller->SetLocalDescription(std::move(reoffer)));
932
933 // Both RtpTransceivers are associated.
934 EXPECT_EQ(first_mid, caller_first_transceiver->mid());
935 EXPECT_EQ(second_mid, caller_second_transceiver->mid());
936}
937
938// Test that a m= section is *not* recycled if the media section is only
939// rejected in the pending local description and not rejected in the current
940// remote description.
941TEST_P(RecycleMediaSectionTest, PendingLocalRejectedAndNotRejectedRemote) {
942 auto caller = CreatePeerConnection();
943 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
944 auto callee = CreatePeerConnection();
945
946 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
947
948 std::string first_mid = *caller_first_transceiver->mid();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200949 caller_first_transceiver->StopInternal();
Steve Anton5c72e712018-12-10 14:25:30 -0800950
951 // The reoffer will have a rejected m= section.
952 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
953
954 auto caller_second_transceiver = caller->AddTransceiver(second_type_);
955
956 // The reoffer should not recycle the existing m= section since it is not
957 // rejected in either the *current* local or *current* remote description.
958 auto reoffer = caller->CreateOffer();
959 auto reoffer_contents = reoffer->description()->contents();
960 ASSERT_EQ(2u, reoffer_contents.size());
961 EXPECT_TRUE(reoffer_contents[0].rejected);
962 EXPECT_EQ(first_type_, reoffer_contents[0].media_description()->type());
963 EXPECT_EQ(first_mid, reoffer_contents[0].name);
964 EXPECT_FALSE(reoffer_contents[1].rejected);
965 EXPECT_EQ(second_type_, reoffer_contents[1].media_description()->type());
966 std::string second_mid = reoffer_contents[1].name;
967 EXPECT_NE(first_mid, second_mid);
968
969 ASSERT_TRUE(caller->SetLocalDescription(std::move(reoffer)));
970
971 // Both RtpTransceivers are associated.
972 EXPECT_EQ(first_mid, caller_first_transceiver->mid());
973 EXPECT_EQ(second_mid, caller_second_transceiver->mid());
974}
975
976// Test that an m= section is *not* recycled if the media section is only
977// rejected in the pending remote description and there is no current local
978// description.
979TEST_P(RecycleMediaSectionTest, PendingRemoteRejectedAndNoLocal) {
980 auto caller = CreatePeerConnection();
981 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
982 auto callee = CreatePeerConnection();
983
984 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
985
986 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
987 auto callee_first_transceiver = callee->pc()->GetTransceivers()[0];
988 std::string first_mid = *callee_first_transceiver->mid();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200989 caller_first_transceiver->StopInternal();
Steve Anton5c72e712018-12-10 14:25:30 -0800990
991 // The reoffer will have a rejected m= section.
992 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
993
994 auto callee_second_transceiver = callee->AddTransceiver(second_type_);
995
996 // The reoffer should not recycle the existing m= section since it is not
997 // rejected in either the *current* local or *current* remote description.
998 auto reoffer = callee->CreateOffer();
999 auto reoffer_contents = reoffer->description()->contents();
1000 ASSERT_EQ(2u, reoffer_contents.size());
1001 EXPECT_TRUE(reoffer_contents[0].rejected);
1002 EXPECT_EQ(first_type_, reoffer_contents[0].media_description()->type());
1003 EXPECT_EQ(first_mid, reoffer_contents[0].name);
1004 EXPECT_FALSE(reoffer_contents[1].rejected);
1005 EXPECT_EQ(second_type_, reoffer_contents[1].media_description()->type());
1006 std::string second_mid = reoffer_contents[1].name;
1007 EXPECT_NE(first_mid, second_mid);
1008
1009 // Note: Cannot actually set the reoffer since the callee is in the signaling
1010 // state 'have-remote-offer'.
1011}
1012
1013// Test that an m= section is *not* recycled if the media section is only
1014// rejected in the pending remote description and not rejected in the current
1015// local description.
1016TEST_P(RecycleMediaSectionTest, PendingRemoteRejectedAndNotRejectedLocal) {
1017 auto caller = CreatePeerConnection();
1018 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
1019 auto callee = CreatePeerConnection();
1020
1021 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1022
1023 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
1024 auto callee_first_transceiver = callee->pc()->GetTransceivers()[0];
1025 std::string first_mid = *callee_first_transceiver->mid();
Harald Alvestrand6060df52020-08-11 09:54:02 +02001026 caller_first_transceiver->StopInternal();
Steve Anton5c72e712018-12-10 14:25:30 -08001027
1028 // The reoffer will have a rejected m= section.
1029 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1030
1031 auto callee_second_transceiver = callee->AddTransceiver(second_type_);
1032
1033 // The reoffer should not recycle the existing m= section since it is not
1034 // rejected in either the *current* local or *current* remote description.
1035 auto reoffer = callee->CreateOffer();
1036 auto reoffer_contents = reoffer->description()->contents();
1037 ASSERT_EQ(2u, reoffer_contents.size());
1038 EXPECT_TRUE(reoffer_contents[0].rejected);
1039 EXPECT_EQ(first_type_, reoffer_contents[0].media_description()->type());
1040 EXPECT_EQ(first_mid, reoffer_contents[0].name);
1041 EXPECT_FALSE(reoffer_contents[1].rejected);
1042 EXPECT_EQ(second_type_, reoffer_contents[1].media_description()->type());
1043 std::string second_mid = reoffer_contents[1].name;
1044 EXPECT_NE(first_mid, second_mid);
1045
1046 // Note: Cannot actually set the reoffer since the callee is in the signaling
1047 // state 'have-remote-offer'.
1048}
1049
Steve Antondcc3c022017-12-22 16:02:54 -08001050// Test all combinations of audio and video as the first and second media type
1051// for the media section. This is needed for full test coverage because
1052// MediaSession has separate functions for processing audio and video media
1053// sections.
Mirko Bonadeic84f6612019-01-31 12:20:57 +01001054INSTANTIATE_TEST_SUITE_P(
Steve Antondcc3c022017-12-22 16:02:54 -08001055 PeerConnectionJsepTest,
1056 RecycleMediaSectionTest,
1057 Combine(Values(cricket::MEDIA_TYPE_AUDIO, cricket::MEDIA_TYPE_VIDEO),
1058 Values(cricket::MEDIA_TYPE_AUDIO, cricket::MEDIA_TYPE_VIDEO)));
1059
Steve Antonfa2260d2017-12-28 16:38:23 -08001060// Test that a new data channel section will not reuse a recycleable audio or
1061// video media section. Additionally, tests that the new section is added to the
1062// end of the session description.
1063TEST_F(PeerConnectionJsepTest, DataChannelDoesNotRecycleMediaSection) {
1064 auto caller = CreatePeerConnection();
1065 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1066 auto callee = CreatePeerConnection();
1067
1068 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1069
Harald Alvestrand6060df52020-08-11 09:54:02 +02001070 transceiver->StopInternal();
Steve Antonfa2260d2017-12-28 16:38:23 -08001071
1072 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1073
1074 caller->CreateDataChannel("dc");
1075
1076 auto offer = caller->CreateOffer();
1077 auto offer_contents = offer->description()->contents();
1078 ASSERT_EQ(2u, offer_contents.size());
1079 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO,
1080 offer_contents[0].media_description()->type());
1081 EXPECT_EQ(cricket::MEDIA_TYPE_DATA,
1082 offer_contents[1].media_description()->type());
1083
1084 ASSERT_TRUE(
1085 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
1086 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1087
1088 auto answer = callee->CreateAnswer();
1089 auto answer_contents = answer->description()->contents();
1090 ASSERT_EQ(2u, answer_contents.size());
1091 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO,
1092 answer_contents[0].media_description()->type());
1093 EXPECT_EQ(cricket::MEDIA_TYPE_DATA,
1094 answer_contents[1].media_description()->type());
1095}
1096
1097// Test that if a new track is added to an existing session that has a data,
1098// the new section comes at the end of the new offer, after the existing data
1099// section.
1100TEST_F(PeerConnectionJsepTest, AudioTrackAddedAfterDataSectionInReoffer) {
1101 auto caller = CreatePeerConnection();
1102 caller->CreateDataChannel("dc");
1103 auto callee = CreatePeerConnection();
1104
1105 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1106
1107 caller->AddAudioTrack("a");
1108
1109 auto offer = caller->CreateOffer();
1110 auto contents = offer->description()->contents();
1111 ASSERT_EQ(2u, contents.size());
1112 EXPECT_EQ(cricket::MEDIA_TYPE_DATA, contents[0].media_description()->type());
1113 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, contents[1].media_description()->type());
1114}
1115
Steve Antondcc3c022017-12-22 16:02:54 -08001116// Tests for MID properties.
1117
1118static void RenameSection(size_t mline_index,
1119 const std::string& new_mid,
1120 SessionDescriptionInterface* sdesc) {
1121 cricket::SessionDescription* desc = sdesc->description();
1122 std::string old_mid = desc->contents()[mline_index].name;
1123 desc->contents()[mline_index].name = new_mid;
1124 desc->transport_infos()[mline_index].content_name = new_mid;
1125 const cricket::ContentGroup* bundle =
1126 desc->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1127 if (bundle) {
1128 cricket::ContentGroup new_bundle = *bundle;
1129 if (new_bundle.RemoveContentName(old_mid)) {
1130 new_bundle.AddContentName(new_mid);
1131 }
1132 desc->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1133 desc->AddGroup(new_bundle);
1134 }
1135}
1136
1137// Test that two PeerConnections can have a successful offer/answer exchange if
1138// the MIDs are changed from the defaults.
1139TEST_F(PeerConnectionJsepTest, OfferAnswerWithChangedMids) {
1140 constexpr char kFirstMid[] = "nondefaultmid";
1141 constexpr char kSecondMid[] = "randommid";
1142
1143 auto caller = CreatePeerConnection();
1144 caller->AddAudioTrack("a");
1145 caller->AddAudioTrack("b");
1146 auto callee = CreatePeerConnection();
1147
1148 auto offer = caller->CreateOffer();
1149 RenameSection(0, kFirstMid, offer.get());
1150 RenameSection(1, kSecondMid, offer.get());
1151
1152 ASSERT_TRUE(
1153 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
1154 auto caller_transceivers = caller->pc()->GetTransceivers();
1155 EXPECT_EQ(kFirstMid, caller_transceivers[0]->mid());
1156 EXPECT_EQ(kSecondMid, caller_transceivers[1]->mid());
1157
1158 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1159 auto callee_transceivers = callee->pc()->GetTransceivers();
1160 EXPECT_EQ(kFirstMid, callee_transceivers[0]->mid());
1161 EXPECT_EQ(kSecondMid, callee_transceivers[1]->mid());
1162
1163 auto answer = callee->CreateAnswer();
1164 auto answer_contents = answer->description()->contents();
1165 EXPECT_EQ(kFirstMid, answer_contents[0].name);
1166 EXPECT_EQ(kSecondMid, answer_contents[1].name);
1167
1168 ASSERT_TRUE(
1169 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
1170 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
1171}
1172
1173// Test that CreateOffer will generate a MID that is not already used if the
1174// default it would have picked is already taken. This is tested by using a
1175// third PeerConnection to determine what the default would be for the second
1176// media section then setting that as the first media section's MID.
1177TEST_F(PeerConnectionJsepTest, CreateOfferGeneratesUniqueMidIfAlreadyTaken) {
1178 // First, find what the default MID is for the second media section.
1179 auto pc = CreatePeerConnection();
1180 pc->AddAudioTrack("a");
1181 pc->AddAudioTrack("b");
1182 auto default_offer = pc->CreateOffer();
1183 std::string default_second_mid =
1184 default_offer->description()->contents()[1].name;
1185
1186 // Now, do an offer/answer with one track which has the MID set to the default
1187 // second MID.
1188 auto caller = CreatePeerConnection();
1189 caller->AddAudioTrack("a");
1190 auto callee = CreatePeerConnection();
1191
1192 auto offer = caller->CreateOffer();
1193 RenameSection(0, default_second_mid, offer.get());
1194
1195 ASSERT_TRUE(
1196 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
1197 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1198 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1199
1200 // Add a second track and ensure that the MID is different.
1201 caller->AddAudioTrack("b");
1202
1203 auto reoffer = caller->CreateOffer();
1204 auto reoffer_contents = reoffer->description()->contents();
1205 EXPECT_EQ(default_second_mid, reoffer_contents[0].name);
1206 EXPECT_NE(reoffer_contents[0].name, reoffer_contents[1].name);
1207}
1208
Steve Antonfa2260d2017-12-28 16:38:23 -08001209// Test that if an audio or video section has the default data section MID, then
1210// CreateOffer will generate a unique MID for the newly added data section.
1211TEST_F(PeerConnectionJsepTest,
1212 CreateOfferGeneratesUniqueMidForDataSectionIfAlreadyTaken) {
1213 // First, find what the default MID is for the data channel.
1214 auto pc = CreatePeerConnection();
1215 pc->CreateDataChannel("dc");
1216 auto default_offer = pc->CreateOffer();
1217 std::string default_data_mid =
1218 default_offer->description()->contents()[0].name;
1219
1220 // Now do an offer/answer with one audio track which has a MID set to the
1221 // default data MID.
1222 auto caller = CreatePeerConnection();
1223 caller->AddAudioTrack("a");
1224 auto callee = CreatePeerConnection();
1225
1226 auto offer = caller->CreateOffer();
1227 RenameSection(0, default_data_mid, offer.get());
1228
1229 ASSERT_TRUE(
1230 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
1231 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1232 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1233
1234 // Add a data channel and ensure that the MID is different.
1235 caller->CreateDataChannel("dc");
1236
1237 auto reoffer = caller->CreateOffer();
1238 auto reoffer_contents = reoffer->description()->contents();
1239 EXPECT_EQ(default_data_mid, reoffer_contents[0].name);
1240 EXPECT_NE(reoffer_contents[0].name, reoffer_contents[1].name);
1241}
1242
Steve Antondcc3c022017-12-22 16:02:54 -08001243// Test that a reoffer initiated by the callee adds a new track to the caller.
1244TEST_F(PeerConnectionJsepTest, CalleeDoesReoffer) {
1245 auto caller = CreatePeerConnection();
1246 caller->AddAudioTrack("a");
1247 auto callee = CreatePeerConnection();
1248 callee->AddAudioTrack("a");
1249 callee->AddVideoTrack("v");
1250
1251 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1252
1253 EXPECT_EQ(1u, caller->pc()->GetTransceivers().size());
1254 EXPECT_EQ(2u, callee->pc()->GetTransceivers().size());
1255
1256 ASSERT_TRUE(callee->ExchangeOfferAnswerWith(caller.get()));
1257
1258 EXPECT_EQ(2u, caller->pc()->GetTransceivers().size());
1259 EXPECT_EQ(2u, callee->pc()->GetTransceivers().size());
1260}
1261
Steve Anton02ee47c2018-01-10 16:26:06 -08001262// Tests for MSID properties.
1263
1264// Test that adding a track with AddTrack results in an offer that signals the
1265// track's ID.
1266TEST_F(PeerConnectionJsepTest, AddingTrackWithAddTrackSpecifiesTrackId) {
1267 const std::string kTrackId = "audio_track";
1268
1269 auto caller = CreatePeerConnection();
1270 caller->AddAudioTrack(kTrackId);
1271
1272 auto offer = caller->CreateOffer();
1273 auto contents = offer->description()->contents();
1274 ASSERT_EQ(1u, contents.size());
1275 auto streams = contents[0].media_description()->streams();
1276 ASSERT_EQ(1u, streams.size());
1277 EXPECT_EQ(kTrackId, streams[0].id);
1278}
1279
1280// Test that adding a track by calling AddTransceiver then SetTrack results in
1281// an offer that does not signal the track's ID and signals a random ID.
1282TEST_F(PeerConnectionJsepTest,
1283 AddingTrackWithAddTransceiverSpecifiesRandomTrackId) {
1284 const std::string kTrackId = "audio_track";
1285
1286 auto caller = CreatePeerConnection();
1287 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1288 transceiver->sender()->SetTrack(caller->CreateAudioTrack(kTrackId));
1289
1290 auto offer = caller->CreateOffer();
1291 auto contents = offer->description()->contents();
1292 ASSERT_EQ(1u, contents.size());
1293 auto streams = contents[0].media_description()->streams();
1294 ASSERT_EQ(1u, streams.size());
1295 EXPECT_NE(kTrackId, streams[0].id);
1296}
1297
Steve Anton5f94aa22018-02-01 10:58:30 -08001298// Test that if the transceiver is recvonly or inactive, then no MSID
1299// information is included in the offer.
1300TEST_F(PeerConnectionJsepTest, NoMsidInOfferIfTransceiverDirectionHasNoSend) {
1301 auto caller = CreatePeerConnection();
1302
1303 RtpTransceiverInit init_recvonly;
1304 init_recvonly.direction = RtpTransceiverDirection::kRecvOnly;
1305 ASSERT_TRUE(caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init_recvonly));
1306
1307 RtpTransceiverInit init_inactive;
1308 init_inactive.direction = RtpTransceiverDirection::kInactive;
1309 ASSERT_TRUE(caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init_inactive));
1310
1311 auto offer = caller->CreateOffer();
1312 auto contents = offer->description()->contents();
1313 ASSERT_EQ(2u, contents.size());
1314 // MSID is specified in the first stream, so no streams means no MSID.
1315 EXPECT_EQ(0u, contents[0].media_description()->streams().size());
1316 EXPECT_EQ(0u, contents[1].media_description()->streams().size());
1317}
1318
1319// Test that if an answer negotiates transceiver directions of recvonly or
1320// inactive, then no MSID information is included in the answer.
1321TEST_F(PeerConnectionJsepTest, NoMsidInAnswerIfNoRespondingTracks) {
1322 auto caller = CreatePeerConnection();
1323 auto callee = CreatePeerConnection();
1324
1325 // recvonly transceiver will get negotiated to inactive since the callee has
1326 // no tracks to send in response.
1327 RtpTransceiverInit init_recvonly;
1328 init_recvonly.direction = RtpTransceiverDirection::kRecvOnly;
1329 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init_recvonly);
1330
1331 // sendrecv transceiver will get negotiated to recvonly since the callee has
1332 // no tracks to send in response.
1333 RtpTransceiverInit init_sendrecv;
1334 init_sendrecv.direction = RtpTransceiverDirection::kSendRecv;
1335 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init_sendrecv);
1336
1337 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1338
1339 auto answer = callee->CreateAnswer();
1340 auto contents = answer->description()->contents();
1341 ASSERT_EQ(2u, contents.size());
1342 // MSID is specified in the first stream, so no streams means no MSID.
1343 EXPECT_EQ(0u, contents[0].media_description()->streams().size());
1344 EXPECT_EQ(0u, contents[1].media_description()->streams().size());
1345}
1346
1347// Test that the MSID is included even if the transceiver direction has changed
1348// to inactive if the transceiver had previously sent media.
1349TEST_F(PeerConnectionJsepTest, IncludeMsidEvenIfDirectionHasChanged) {
1350 auto caller = CreatePeerConnection();
1351 caller->AddAudioTrack("audio");
1352 auto callee = CreatePeerConnection();
1353 callee->AddAudioTrack("audio");
1354
1355 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1356
Harald Alvestrand6060df52020-08-11 09:54:02 +02001357 caller->pc()->GetTransceivers()[0]->SetDirectionWithError(
Steve Anton5f94aa22018-02-01 10:58:30 -08001358 RtpTransceiverDirection::kInactive);
1359
1360 // The transceiver direction on both sides will turn to inactive.
1361 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1362
1363 auto* offer = callee->pc()->remote_description();
1364 auto offer_contents = offer->description()->contents();
1365 ASSERT_EQ(1u, offer_contents.size());
1366 // MSID is specified in the first stream. If it is present, assume that MSID
1367 // is there.
1368 EXPECT_EQ(1u, offer_contents[0].media_description()->streams().size());
1369
1370 auto* answer = caller->pc()->remote_description();
1371 auto answer_contents = answer->description()->contents();
1372 ASSERT_EQ(1u, answer_contents.size());
1373 EXPECT_EQ(1u, answer_contents[0].media_description()->streams().size());
1374}
1375
1376// Test that stopping a RtpTransceiver will cause future offers to not include
1377// any MSID information for that section.
1378TEST_F(PeerConnectionJsepTest, RemoveMsidIfTransceiverStopped) {
1379 auto caller = CreatePeerConnection();
1380 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1381 auto callee = CreatePeerConnection();
1382
1383 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1384
Harald Alvestrand6060df52020-08-11 09:54:02 +02001385 transceiver->StopInternal();
Steve Anton5f94aa22018-02-01 10:58:30 -08001386
1387 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1388
1389 auto* offer = callee->pc()->remote_description();
1390 auto offer_contents = offer->description()->contents();
1391 ASSERT_EQ(1u, offer_contents.size());
1392 // MSID is specified in the first stream, so no streams means no MSID.
1393 EXPECT_EQ(0u, offer_contents[0].media_description()->streams().size());
1394}
1395
Steve Anton02ee47c2018-01-10 16:26:06 -08001396// Test that the callee RtpReceiver created by a call to SetRemoteDescription
1397// has its ID set to the signaled track ID.
1398TEST_F(PeerConnectionJsepTest,
1399 RtpReceiverCreatedBySetRemoteDescriptionHasSignaledTrackId) {
1400 const std::string kTrackId = "audio_track";
1401
1402 auto caller = CreatePeerConnection();
1403 auto callee = CreatePeerConnection();
1404 caller->AddAudioTrack(kTrackId);
1405
1406 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1407
1408 ASSERT_EQ(1u, callee->pc()->GetReceivers().size());
1409 auto receiver = callee->pc()->GetReceivers()[0];
1410 EXPECT_EQ(kTrackId, receiver->id());
1411}
1412
1413// Test that if the callee RtpReceiver is reused by a call to
1414// SetRemoteDescription, its ID does not change.
1415TEST_F(PeerConnectionJsepTest,
1416 RtpReceiverCreatedBeforeSetRemoteDescriptionKeepsId) {
1417 const std::string kTrackId = "audio_track";
1418
1419 auto caller = CreatePeerConnection();
1420 auto callee = CreatePeerConnection();
1421 caller->AddAudioTrack(kTrackId);
1422 callee->AddAudioTrack("dummy_track");
1423
1424 ASSERT_EQ(1u, callee->pc()->GetReceivers().size());
1425 auto receiver = callee->pc()->GetReceivers()[0];
1426 std::string receiver_id = receiver->id();
1427
1428 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1429
1430 EXPECT_EQ(receiver_id, receiver->id());
1431}
1432
Steve Antonef65ef12018-01-10 17:15:20 -08001433// Test that setting a remote offer with one track that has no streams fires off
1434// the correct OnAddTrack event.
1435TEST_F(PeerConnectionJsepTest,
1436 SetRemoteOfferWithOneTrackNoStreamFiresOnAddTrack) {
1437 const std::string kTrackLabel = "audio_track";
1438
1439 auto caller = CreatePeerConnection();
1440 auto callee = CreatePeerConnection();
1441 ASSERT_TRUE(caller->AddAudioTrack(kTrackLabel));
1442
1443 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1444
Seth Hampson5b4f0752018-04-02 16:31:36 -07001445 const auto& track_events = callee->observer()->add_track_events_;
1446 ASSERT_EQ(1u, track_events.size());
1447 const auto& event = track_events[0];
1448 EXPECT_EQ(kTrackLabel, event.receiver->track()->id());
1449 EXPECT_EQ(0u, event.streams.size());
Steve Antonef65ef12018-01-10 17:15:20 -08001450}
1451
1452// Test that setting a remote offer with one track that has one stream fires off
1453// the correct OnAddTrack event.
1454TEST_F(PeerConnectionJsepTest,
1455 SetRemoteOfferWithOneTrackOneStreamFiresOnAddTrack) {
1456 const std::string kTrackLabel = "audio_track";
Seth Hampson845e8782018-03-02 11:34:10 -08001457 const std::string kStreamId = "audio_stream";
Steve Antonef65ef12018-01-10 17:15:20 -08001458
1459 auto caller = CreatePeerConnection();
1460 auto callee = CreatePeerConnection();
Seth Hampson845e8782018-03-02 11:34:10 -08001461 ASSERT_TRUE(caller->AddAudioTrack(kTrackLabel, {kStreamId}));
Steve Antonef65ef12018-01-10 17:15:20 -08001462
1463 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1464
1465 const auto& track_events = callee->observer()->add_track_events_;
1466 ASSERT_EQ(1u, track_events.size());
1467 const auto& event = track_events[0];
1468 ASSERT_EQ(1u, event.streams.size());
1469 auto stream = event.streams[0];
Seth Hampson13b8bad2018-03-13 16:05:28 -07001470 EXPECT_EQ(kStreamId, stream->id());
Steve Antonef65ef12018-01-10 17:15:20 -08001471 EXPECT_THAT(track_events[0].snapshotted_stream_tracks.at(stream),
1472 ElementsAre(event.receiver->track()));
1473 EXPECT_EQ(event.receiver->streams(), track_events[0].streams);
1474}
1475
1476// Test that setting a remote offer with two tracks that share the same stream
1477// fires off two OnAddTrack events, both with the same stream that has both
1478// tracks present at the time of firing. This is to ensure that track events are
1479// not fired until SetRemoteDescription has finished processing all the media
1480// sections.
1481TEST_F(PeerConnectionJsepTest,
1482 SetRemoteOfferWithTwoTracksSameStreamFiresOnAddTrack) {
1483 const std::string kTrack1Label = "audio_track1";
1484 const std::string kTrack2Label = "audio_track2";
Seth Hampson845e8782018-03-02 11:34:10 -08001485 const std::string kSharedStreamId = "stream";
Steve Antonef65ef12018-01-10 17:15:20 -08001486
1487 auto caller = CreatePeerConnection();
1488 auto callee = CreatePeerConnection();
Seth Hampson845e8782018-03-02 11:34:10 -08001489 ASSERT_TRUE(caller->AddAudioTrack(kTrack1Label, {kSharedStreamId}));
1490 ASSERT_TRUE(caller->AddAudioTrack(kTrack2Label, {kSharedStreamId}));
Steve Antonef65ef12018-01-10 17:15:20 -08001491
1492 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1493
1494 const auto& track_events = callee->observer()->add_track_events_;
1495 ASSERT_EQ(2u, track_events.size());
1496 const auto& event1 = track_events[0];
1497 const auto& event2 = track_events[1];
1498 ASSERT_EQ(1u, event1.streams.size());
1499 auto stream = event1.streams[0];
1500 ASSERT_THAT(event2.streams, ElementsAre(stream));
1501 auto track1 = event1.receiver->track();
1502 auto track2 = event2.receiver->track();
1503 EXPECT_THAT(event1.snapshotted_stream_tracks.at(stream),
1504 UnorderedElementsAre(track1, track2));
1505 EXPECT_THAT(event2.snapshotted_stream_tracks.at(stream),
1506 UnorderedElementsAre(track1, track2));
1507}
1508
Seth Hampson5b4f0752018-04-02 16:31:36 -07001509// Test that setting a remote offer with one track that has two streams fires
1510// off the correct OnAddTrack event.
1511TEST_F(PeerConnectionJsepTest,
1512 SetRemoteOfferWithOneTrackTwoStreamFiresOnAddTrack) {
1513 const std::string kTrackLabel = "audio_track";
1514 const std::string kStreamId1 = "audio_stream1";
1515 const std::string kStreamId2 = "audio_stream2";
1516
1517 auto caller = CreatePeerConnection();
1518 auto callee = CreatePeerConnection();
1519 ASSERT_TRUE(caller->AddAudioTrack(kTrackLabel, {kStreamId1, kStreamId2}));
1520
1521 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1522
1523 const auto& track_events = callee->observer()->add_track_events_;
1524 ASSERT_EQ(1u, track_events.size());
1525 const auto& event = track_events[0];
1526 ASSERT_EQ(2u, event.streams.size());
1527 EXPECT_EQ(kStreamId1, event.streams[0]->id());
1528 EXPECT_EQ(kStreamId2, event.streams[1]->id());
1529}
Steve Antonef65ef12018-01-10 17:15:20 -08001530
Steve Anton54b84072018-02-20 15:19:52 -08001531// Test that if an RtpTransceiver with a current_direction set is stopped, then
1532// current_direction is changed to null.
1533TEST_F(PeerConnectionJsepTest, CurrentDirectionResetWhenRtpTransceiverStopped) {
1534 auto caller = CreatePeerConnection();
1535 auto callee = CreatePeerConnection();
1536
1537 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1538
1539 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1540
1541 ASSERT_TRUE(transceiver->current_direction());
Harald Alvestrand6060df52020-08-11 09:54:02 +02001542 transceiver->StopInternal();
1543 EXPECT_EQ(transceiver->current_direction(),
1544 RtpTransceiverDirection::kStopped);
Steve Anton54b84072018-02-20 15:19:52 -08001545}
1546
Steve Antonba42e992018-04-09 14:10:01 -07001547// Test that you can't set an answer on a PeerConnection before setting the
1548// offer.
Harald Alvestrand5081c0c2018-03-09 15:18:03 +01001549TEST_F(PeerConnectionJsepTest, AnswerBeforeOfferFails) {
1550 auto caller = CreatePeerConnection();
1551 auto callee = CreatePeerConnection();
Harald Alvestrand5081c0c2018-03-09 15:18:03 +01001552 caller->AddAudioTrack("audio");
Steve Antonba42e992018-04-09 14:10:01 -07001553
1554 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1555
1556 RTCError error;
1557 ASSERT_FALSE(caller->SetRemoteDescription(callee->CreateAnswer(), &error));
1558 EXPECT_EQ(RTCErrorType::INVALID_STATE, error.type());
1559}
1560
1561// Test that a Unified Plan PeerConnection fails to set a Plan B offer if it has
1562// two video tracks.
1563TEST_F(PeerConnectionJsepTest, TwoVideoPlanBToUnifiedPlanFails) {
1564 RTCConfiguration config_planb;
1565 config_planb.sdp_semantics = SdpSemantics::kPlanB;
1566 auto caller = CreatePeerConnection(config_planb);
1567 auto callee = CreatePeerConnection();
1568 caller->AddVideoTrack("video1");
1569 caller->AddVideoTrack("video2");
1570
1571 RTCError error;
1572 ASSERT_FALSE(callee->SetRemoteDescription(caller->CreateOffer(), &error));
1573 EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, error.type());
1574}
1575
1576// Test that a Unified Plan PeerConnection fails to set a Plan B answer if it
1577// has two video tracks.
1578TEST_F(PeerConnectionJsepTest, OneVideoUnifiedPlanToTwoVideoPlanBFails) {
1579 auto caller = CreatePeerConnection();
1580 RTCConfiguration config_planb;
1581 config_planb.sdp_semantics = SdpSemantics::kPlanB;
1582 auto callee = CreatePeerConnection(config_planb);
1583 caller->AddVideoTrack("video");
1584 callee->AddVideoTrack("video1");
1585 callee->AddVideoTrack("video2");
1586
1587 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1588
1589 RTCError error;
1590 ASSERT_FALSE(caller->SetRemoteDescription(caller->CreateAnswer(), &error));
1591 EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, error.type());
Harald Alvestrand5081c0c2018-03-09 15:18:03 +01001592}
1593
Steve Anton06817cd2018-12-18 15:55:30 -08001594// Removes the RTP header extension associated with the given URI from the media
1595// description.
1596static void RemoveRtpHeaderExtensionByUri(
1597 MediaContentDescription* media_description,
1598 absl::string_view uri) {
1599 std::vector<RtpExtension> header_extensions =
1600 media_description->rtp_header_extensions();
1601 header_extensions.erase(std::remove_if(
1602 header_extensions.begin(), header_extensions.end(),
1603 [uri](const RtpExtension& extension) { return extension.uri == uri; }));
1604 media_description->set_rtp_header_extensions(header_extensions);
1605}
1606
1607// Transforms a session description to emulate a legacy endpoint which does not
1608// support a=mid, BUNDLE, and the MID header extension.
1609static void ClearMids(SessionDescriptionInterface* sdesc) {
1610 cricket::SessionDescription* desc = sdesc->description();
1611 desc->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1612 cricket::ContentInfo* audio_content = cricket::GetFirstAudioContent(desc);
1613 if (audio_content) {
1614 desc->GetTransportInfoByName(audio_content->name)->content_name = "";
1615 audio_content->name = "";
1616 RemoveRtpHeaderExtensionByUri(audio_content->media_description(),
1617 RtpExtension::kMidUri);
1618 }
1619 cricket::ContentInfo* video_content = cricket::GetFirstVideoContent(desc);
1620 if (video_content) {
1621 desc->GetTransportInfoByName(video_content->name)->content_name = "";
1622 video_content->name = "";
1623 RemoveRtpHeaderExtensionByUri(video_content->media_description(),
1624 RtpExtension::kMidUri);
1625 }
1626}
1627
1628// Test that negotiation works with legacy endpoints which do not support a=mid.
1629TEST_F(PeerConnectionJsepTest, LegacyNoMidAudioOnlyOffer) {
1630 auto caller = CreatePeerConnection();
1631 caller->AddAudioTrack("audio");
1632 auto callee = CreatePeerConnection();
1633 callee->AddAudioTrack("audio");
1634
1635 auto offer = caller->CreateOffer();
1636 ClearMids(offer.get());
1637
1638 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1639 EXPECT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1640}
1641TEST_F(PeerConnectionJsepTest, LegacyNoMidAudioVideoOffer) {
1642 auto caller = CreatePeerConnection();
1643 caller->AddAudioTrack("audio");
1644 caller->AddVideoTrack("video");
1645 auto callee = CreatePeerConnection();
1646 callee->AddAudioTrack("audio");
1647 callee->AddVideoTrack("video");
1648
1649 auto offer = caller->CreateOffer();
1650 ClearMids(offer.get());
1651
1652 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1653 EXPECT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1654}
1655TEST_F(PeerConnectionJsepTest, LegacyNoMidAudioOnlyAnswer) {
1656 auto caller = CreatePeerConnection();
1657 caller->AddAudioTrack("audio");
1658 auto callee = CreatePeerConnection();
1659 callee->AddAudioTrack("audio");
1660
1661 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1662
1663 auto answer = callee->CreateAnswer();
1664 ClearMids(answer.get());
1665
1666 EXPECT_TRUE(caller->SetRemoteDescription(std::move(answer)));
1667}
1668TEST_F(PeerConnectionJsepTest, LegacyNoMidAudioVideoAnswer) {
1669 auto caller = CreatePeerConnection();
1670 caller->AddAudioTrack("audio");
1671 caller->AddVideoTrack("video");
1672 auto callee = CreatePeerConnection();
1673 callee->AddAudioTrack("audio");
1674 callee->AddVideoTrack("video");
1675
1676 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1677
1678 auto answer = callee->CreateAnswer();
1679 ClearMids(answer.get());
1680
1681 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
1682}
1683
Steve Antond7180cc2019-02-07 10:44:53 -08001684// Test that negotiation works with legacy endpoints which do not support a=mid
1685// when setting two remote descriptions without setting a local description in
1686// between.
1687TEST_F(PeerConnectionJsepTest, LegacyNoMidTwoRemoteOffers) {
1688 auto caller = CreatePeerConnection();
1689 caller->AddAudioTrack("audio");
1690 auto callee = CreatePeerConnection();
1691 callee->AddAudioTrack("audio");
1692
1693 auto offer = caller->CreateOffer();
1694 ClearMids(offer.get());
1695
1696 ASSERT_TRUE(
1697 callee->SetRemoteDescription(CloneSessionDescription(offer.get())));
1698 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1699 EXPECT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1700}
1701
Steve Antonceac0152018-12-19 11:32:20 -08001702// Test that SetLocalDescription fails if a=mid lines are missing.
1703TEST_F(PeerConnectionJsepTest, SetLocalDescriptionFailsMissingMid) {
1704 auto caller = CreatePeerConnection();
1705 caller->AddAudioTrack("audio");
1706
1707 auto offer = caller->CreateOffer();
1708 ClearMids(offer.get());
1709
1710 std::string error;
1711 ASSERT_FALSE(caller->SetLocalDescription(std::move(offer), &error));
1712 EXPECT_EQ(
1713 "Failed to set local offer sdp: A media section is missing a MID "
1714 "attribute.",
1715 error);
1716}
1717
Eldar Rello5ab79e62019-10-09 18:29:44 +03001718TEST_F(PeerConnectionJsepTest, RollbackSupportedInUnifiedPlan) {
1719 RTCConfiguration config;
1720 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
1721 config.enable_implicit_rollback = true;
1722 auto caller = CreatePeerConnection(config);
1723 auto callee = CreatePeerConnection(config);
1724 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
1725 EXPECT_TRUE(caller->SetLocalDescription(caller->CreateRollback()));
1726 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
1727 EXPECT_TRUE(caller->SetRemoteDescription(caller->CreateRollback()));
1728 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
1729 EXPECT_TRUE(caller->SetRemoteDescription(callee->CreateOffer()));
1730}
1731
1732TEST_F(PeerConnectionJsepTest, RollbackNotSupportedInPlanB) {
1733 RTCConfiguration config;
1734 config.sdp_semantics = SdpSemantics::kPlanB;
1735 config.enable_implicit_rollback = true;
1736 auto caller = CreatePeerConnection(config);
1737 auto callee = CreatePeerConnection(config);
1738 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
1739 EXPECT_FALSE(caller->SetLocalDescription(caller->CreateRollback()));
1740 EXPECT_FALSE(caller->SetRemoteDescription(caller->CreateRollback()));
1741 EXPECT_FALSE(caller->SetRemoteDescription(callee->CreateOffer()));
1742}
1743
1744TEST_F(PeerConnectionJsepTest, RollbackFailsInStableState) {
1745 auto caller = CreatePeerConnection();
1746 EXPECT_FALSE(caller->SetLocalDescription(caller->CreateRollback()));
1747 EXPECT_FALSE(caller->SetRemoteDescription(caller->CreateRollback()));
1748}
1749
1750TEST_F(PeerConnectionJsepTest, RollbackToStableStateAndClearLocalOffer) {
1751 auto caller = CreatePeerConnection();
1752 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
1753 EXPECT_TRUE(caller->SetLocalDescription(caller->CreateRollback()));
1754 EXPECT_EQ(caller->signaling_state(), PeerConnectionInterface::kStable);
1755 EXPECT_EQ(caller->pc()->pending_local_description(), nullptr);
1756
1757 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
1758 EXPECT_TRUE(caller->SetRemoteDescription(caller->CreateRollback()));
1759 EXPECT_EQ(caller->signaling_state(), PeerConnectionInterface::kStable);
1760 EXPECT_EQ(caller->pc()->pending_local_description(), nullptr);
1761}
1762
1763TEST_F(PeerConnectionJsepTest, RollbackToStableStateAndClearRemoteOffer) {
1764 auto caller = CreatePeerConnection();
1765 auto callee = CreatePeerConnection();
1766 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1767 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
1768 EXPECT_EQ(callee->signaling_state(), PeerConnectionInterface::kStable);
1769 EXPECT_EQ(callee->pc()->pending_remote_description(), nullptr);
1770
1771 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1772 EXPECT_TRUE(callee->SetLocalDescription(caller->CreateRollback()));
1773 EXPECT_EQ(callee->signaling_state(), PeerConnectionInterface::kStable);
1774 EXPECT_EQ(callee->pc()->pending_remote_description(), nullptr);
1775}
1776
Eldar Relloead0ec92019-10-21 23:01:31 +03001777TEST_F(PeerConnectionJsepTest, RollbackImplicitly) {
Eldar Rello5ab79e62019-10-09 18:29:44 +03001778 RTCConfiguration config;
1779 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
1780 config.enable_implicit_rollback = true;
1781 auto caller = CreatePeerConnection(config);
1782 auto callee = CreatePeerConnection(config);
1783 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
1784 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1785 EXPECT_EQ(callee->signaling_state(),
1786 PeerConnectionInterface::kHaveRemoteOffer);
Eldar Relloead0ec92019-10-21 23:01:31 +03001787 EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal());
Henrik Boströme574a312020-08-25 10:20:11 +02001788 EXPECT_FALSE(callee->observer()->legacy_renegotiation_needed());
1789 EXPECT_FALSE(callee->observer()->has_negotiation_needed_event());
Eldar Rello5ab79e62019-10-09 18:29:44 +03001790}
1791
Eldar Relloead0ec92019-10-21 23:01:31 +03001792TEST_F(PeerConnectionJsepTest, RollbackImplicitlyNegotatiationNotNeeded) {
1793 RTCConfiguration config;
1794 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
1795 config.enable_implicit_rollback = true;
1796 auto caller = CreatePeerConnection(config);
1797 auto callee = CreatePeerConnection(config);
1798 caller->AddAudioTrack("a");
1799 callee->AddAudioTrack("b");
1800 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
Henrik Boströme574a312020-08-25 10:20:11 +02001801 callee->observer()->clear_legacy_renegotiation_needed();
1802 callee->observer()->clear_latest_negotiation_needed_event();
Eldar Relloead0ec92019-10-21 23:01:31 +03001803 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1804 EXPECT_EQ(callee->signaling_state(),
1805 PeerConnectionInterface::kHaveRemoteOffer);
1806 EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal());
1807 // No negotiation needed as track got attached in the answer.
Henrik Boströme574a312020-08-25 10:20:11 +02001808 EXPECT_FALSE(callee->observer()->legacy_renegotiation_needed());
1809 EXPECT_FALSE(callee->observer()->has_negotiation_needed_event());
Eldar Relloead0ec92019-10-21 23:01:31 +03001810 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 0u);
1811}
1812
1813TEST_F(PeerConnectionJsepTest, RollbackImplicitlyAndNegotiationNeeded) {
1814 RTCConfiguration config;
1815 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
1816 config.enable_implicit_rollback = true;
1817 auto caller = CreatePeerConnection(config);
1818 auto callee = CreatePeerConnection(config);
1819 callee->AddAudioTrack("a");
1820 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
Henrik Boströme574a312020-08-25 10:20:11 +02001821 callee->observer()->clear_legacy_renegotiation_needed();
1822 callee->observer()->clear_latest_negotiation_needed_event();
Eldar Relloead0ec92019-10-21 23:01:31 +03001823 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1824 EXPECT_EQ(callee->signaling_state(),
1825 PeerConnectionInterface::kHaveRemoteOffer);
Henrik Boströme574a312020-08-25 10:20:11 +02001826 EXPECT_FALSE(callee->observer()->legacy_renegotiation_needed());
1827 EXPECT_FALSE(callee->observer()->has_negotiation_needed_event());
Eldar Relloead0ec92019-10-21 23:01:31 +03001828 EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal());
Henrik Boströme574a312020-08-25 10:20:11 +02001829 EXPECT_TRUE(callee->observer()->legacy_renegotiation_needed());
1830 EXPECT_TRUE(callee->observer()->has_negotiation_needed_event());
Eldar Relloead0ec92019-10-21 23:01:31 +03001831 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 0u);
1832}
1833
1834TEST_F(PeerConnectionJsepTest, AttemptToRollbackImplicitly) {
Eldar Rello5ab79e62019-10-09 18:29:44 +03001835 RTCConfiguration config;
1836 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
1837 config.enable_implicit_rollback = true;
1838 auto caller = CreatePeerConnection(config);
1839 auto callee = CreatePeerConnection(config);
1840 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
1841 EXPECT_FALSE(callee->SetRemoteDescription(
1842 CreateSessionDescription(SdpType::kOffer, "invalid sdp")));
1843 EXPECT_EQ(callee->signaling_state(),
1844 PeerConnectionInterface::kHaveLocalOffer);
1845}
1846
1847TEST_F(PeerConnectionJsepTest, RollbackRemovesTransceiver) {
1848 auto caller = CreatePeerConnection();
1849 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1850 auto callee = CreatePeerConnection();
1851 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
Eldar Relloead0ec92019-10-21 23:01:31 +03001852 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
Eldar Rello5ab79e62019-10-09 18:29:44 +03001853 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
Eldar Relloead0ec92019-10-21 23:01:31 +03001854 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 0u);
1855 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 1u);
Eldar Rello5ab79e62019-10-09 18:29:44 +03001856}
1857
1858TEST_F(PeerConnectionJsepTest, RollbackKeepsTransceiverAndClearsMid) {
1859 auto caller = CreatePeerConnection();
1860 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1861 auto callee = CreatePeerConnection();
1862 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1863 callee->AddAudioTrack("a");
Eldar Relloead0ec92019-10-21 23:01:31 +03001864 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
Eldar Rello5ab79e62019-10-09 18:29:44 +03001865 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
1866 // Transceiver can't be removed as track was added to it.
Eldar Relloead0ec92019-10-21 23:01:31 +03001867 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
Eldar Rello5ab79e62019-10-09 18:29:44 +03001868 // Mid got cleared to make it reusable.
1869 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), absl::nullopt);
1870 // Transceiver should be counted as addTrack-created after rollback.
1871 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
Eldar Relloead0ec92019-10-21 23:01:31 +03001872 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
1873 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 1u);
Eldar Rello5ab79e62019-10-09 18:29:44 +03001874}
1875
Eldar Rello353a7182019-11-25 18:49:44 +02001876TEST_F(PeerConnectionJsepTest,
1877 RollbackKeepsTransceiverAfterAddTrackEvenWhenTrackIsNulled) {
1878 auto caller = CreatePeerConnection();
1879 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1880 auto callee = CreatePeerConnection();
1881 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1882 callee->AddAudioTrack("a");
1883 callee->pc()->GetTransceivers()[0]->sender()->SetTrack(nullptr);
1884 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->sender()->track(), nullptr);
1885 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
1886 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
1887 // Transceiver can't be removed as track was added to it.
1888 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
1889 // Mid got cleared to make it reusable.
1890 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), absl::nullopt);
1891 // Transceiver should be counted as addTrack-created after rollback.
1892 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1893 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
1894 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 1u);
1895}
1896
Eldar Rello5ab79e62019-10-09 18:29:44 +03001897TEST_F(PeerConnectionJsepTest, RollbackRestoresMid) {
1898 auto caller = CreatePeerConnection();
1899 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1900 auto callee = CreatePeerConnection();
1901 callee->AddAudioTrack("a");
1902 auto offer = callee->CreateOffer();
1903 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
Eldar Relloead0ec92019-10-21 23:01:31 +03001904 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
Eldar Rello5ab79e62019-10-09 18:29:44 +03001905 EXPECT_NE(callee->pc()->GetTransceivers()[0]->mid(), absl::nullopt);
1906 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
1907 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), absl::nullopt);
1908 EXPECT_TRUE(callee->SetLocalDescription(std::move(offer)));
1909}
1910
1911TEST_F(PeerConnectionJsepTest, RollbackRestoresMidAndRemovesTransceiver) {
1912 auto callee = CreatePeerConnection();
1913 callee->AddVideoTrack("a");
1914 auto offer = callee->CreateOffer();
1915 auto caller = CreatePeerConnection();
1916 caller->AddAudioTrack("b");
1917 caller->AddVideoTrack("c");
1918 auto mid = callee->pc()->GetTransceivers()[0]->mid();
1919 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
Eldar Relloead0ec92019-10-21 23:01:31 +03001920 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 2u);
Eldar Rello5ab79e62019-10-09 18:29:44 +03001921 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
Eldar Relloead0ec92019-10-21 23:01:31 +03001922 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
Eldar Rello5ab79e62019-10-09 18:29:44 +03001923 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), mid);
1924 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->media_type(),
1925 cricket::MEDIA_TYPE_VIDEO);
1926 EXPECT_TRUE(callee->SetLocalDescription(std::move(offer)));
Eldar Relloead0ec92019-10-21 23:01:31 +03001927 EXPECT_EQ(callee->observer()->remove_track_events_.size(),
1928 callee->observer()->add_track_events_.size());
1929}
1930
1931TEST_F(PeerConnectionJsepTest, RollbackHasNoEffectOnStableTransceivers) {
1932 auto callee = CreatePeerConnection();
1933 callee->AddVideoTrack("a");
1934 auto caller = CreatePeerConnection();
1935 caller->AddAudioTrack("b");
1936 caller->AddVideoTrack("c");
1937 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1938 EXPECT_TRUE(
1939 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1940 // In stable don't add or remove anything.
Henrik Boströme574a312020-08-25 10:20:11 +02001941 callee->observer()->clear_legacy_renegotiation_needed();
1942 callee->observer()->clear_latest_negotiation_needed_event();
Eldar Relloead0ec92019-10-21 23:01:31 +03001943 size_t transceiver_count = callee->pc()->GetTransceivers().size();
1944 auto mid_0 = callee->pc()->GetTransceivers()[0]->mid();
1945 auto mid_1 = callee->pc()->GetTransceivers()[1]->mid();
1946 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1947 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
1948 EXPECT_EQ(callee->pc()->GetTransceivers().size(), transceiver_count);
1949 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), mid_0);
1950 EXPECT_EQ(callee->pc()->GetTransceivers()[1]->mid(), mid_1);
1951 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 0u);
Henrik Boströme574a312020-08-25 10:20:11 +02001952 EXPECT_FALSE(callee->observer()->legacy_renegotiation_needed());
1953 EXPECT_FALSE(callee->observer()->has_negotiation_needed_event());
Eldar Rello5ab79e62019-10-09 18:29:44 +03001954}
1955
1956TEST_F(PeerConnectionJsepTest, ImplicitlyRollbackTransceiversWithSameMids) {
1957 RTCConfiguration config;
1958 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
1959 config.enable_implicit_rollback = true;
1960 auto caller = CreatePeerConnection(config);
1961 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
1962 auto callee = CreatePeerConnection(config);
1963 callee->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
1964 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
1965 auto initial_mid = callee->pc()->GetTransceivers()[0]->mid();
1966 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
Eldar Relloead0ec92019-10-21 23:01:31 +03001967 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 2u);
Eldar Rello5ab79e62019-10-09 18:29:44 +03001968 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), absl::nullopt);
1969 EXPECT_EQ(callee->pc()->GetTransceivers()[1]->mid(),
1970 caller->pc()->GetTransceivers()[0]->mid());
1971 EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal()); // Go to stable.
1972 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
1973 EXPECT_NE(callee->pc()->GetTransceivers()[0]->mid(), initial_mid);
1974}
1975
1976TEST_F(PeerConnectionJsepTest, RollbackToNegotiatedStableState) {
1977 RTCConfiguration config;
1978 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
1979 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
1980 auto caller = CreatePeerConnection(config);
1981 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1982 auto callee = CreatePeerConnection(config);
1983 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1984 EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal());
1985 caller->AddVideoTrack("a");
1986 callee->AddVideoTrack("b");
1987 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
Eldar Relloead0ec92019-10-21 23:01:31 +03001988 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 2u);
Eldar Rello5ab79e62019-10-09 18:29:44 +03001989 auto audio_transport =
1990 callee->pc()->GetTransceivers()[0]->sender()->dtls_transport();
1991 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
1992 callee->pc()->GetTransceivers()[1]->sender()->dtls_transport());
1993 EXPECT_NE(callee->pc()->GetTransceivers()[1]->sender()->dtls_transport(),
1994 nullptr);
1995 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
1996 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
1997 audio_transport); // Audio must remain working after rollback.
1998 EXPECT_EQ(callee->pc()->GetTransceivers()[1]->sender()->dtls_transport(),
1999 nullptr);
2000 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2001
2002 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
2003 audio_transport); // Audio transport is still the same.
2004}
2005
Eldar Rello353a7182019-11-25 18:49:44 +02002006TEST_F(PeerConnectionJsepTest, RollbackHasToDestroyTransport) {
2007 RTCConfiguration config;
2008 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
2009 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
2010 auto pc = CreatePeerConnection(config);
2011 pc->AddAudioTrack("a");
2012 pc->AddVideoTrack("b");
2013 EXPECT_TRUE(pc->CreateOfferAndSetAsLocal());
2014 auto offer = pc->CreateOffer();
2015 EXPECT_EQ(pc->pc()->GetTransceivers().size(), 2u);
2016 auto audio_transport =
2017 pc->pc()->GetTransceivers()[0]->sender()->dtls_transport();
2018 EXPECT_EQ(pc->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
2019 pc->pc()->GetTransceivers()[1]->sender()->dtls_transport());
2020 EXPECT_NE(pc->pc()->GetTransceivers()[1]->sender()->dtls_transport(),
2021 nullptr);
2022 EXPECT_TRUE(pc->SetRemoteDescription(pc->CreateRollback()));
2023 EXPECT_TRUE(pc->SetLocalDescription(std::move(offer)));
2024 EXPECT_NE(pc->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
2025 nullptr);
2026 EXPECT_NE(pc->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
2027 audio_transport);
2028}
2029
Eldar Relloead0ec92019-10-21 23:01:31 +03002030TEST_F(PeerConnectionJsepTest, RollbackLocalDirectionChange) {
2031 auto caller = CreatePeerConnection();
2032 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
2033 auto callee = CreatePeerConnection();
2034 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2035 EXPECT_TRUE(
2036 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
2037 callee->AddAudioTrack("a");
Harald Alvestrand6060df52020-08-11 09:54:02 +02002038 callee->pc()->GetTransceivers()[0]->SetDirectionWithError(
Eldar Relloead0ec92019-10-21 23:01:31 +03002039 RtpTransceiverDirection::kSendOnly);
2040 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2041 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
2042 auto audio_transport =
2043 callee->pc()->GetTransceivers()[0]->receiver()->dtls_transport();
2044 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
2045 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->direction(),
2046 RtpTransceiverDirection::kSendOnly);
2047 // One way audio must remain working after rollback as local direction change
2048 // comes in effect after completing full negotiation round.
2049 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->receiver()->dtls_transport(),
2050 audio_transport);
2051}
2052
2053TEST_F(PeerConnectionJsepTest, RollbackRemoteDirectionChange) {
2054 auto caller = CreatePeerConnection();
2055 auto caller_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
2056 auto callee = CreatePeerConnection();
2057 callee->AddAudioTrack("a");
2058 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2059 EXPECT_TRUE(
2060 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
2061 // In stable make remote audio receive only.
Harald Alvestrand6060df52020-08-11 09:54:02 +02002062 caller_transceiver->SetDirectionWithError(RtpTransceiverDirection::kRecvOnly);
Eldar Relloead0ec92019-10-21 23:01:31 +03002063 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2064 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
2065 // The direction attribute is not modified by the offer.
2066 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->direction(),
2067 RtpTransceiverDirection::kSendRecv);
2068 auto audio_transport =
2069 callee->pc()->GetTransceivers()[0]->sender()->dtls_transport();
2070 EXPECT_EQ(callee->observer()->add_track_events_.size(), 1u);
2071 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 1u);
2072 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
2073 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
2074 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->direction(),
2075 RtpTransceiverDirection::kSendRecv);
2076 // One way audio must remain working after rollback.
2077 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
2078 audio_transport);
2079 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 1u);
2080}
2081
Eldar Rello5ab79e62019-10-09 18:29:44 +03002082TEST_F(PeerConnectionJsepTest, RollbackAfterMultipleSLD) {
2083 auto callee = CreatePeerConnection();
2084 callee->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
2085 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2086 callee->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2087 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
Henrik Boströme574a312020-08-25 10:20:11 +02002088 callee->observer()->clear_legacy_renegotiation_needed();
2089 callee->observer()->clear_latest_negotiation_needed_event();
Eldar Rello5ab79e62019-10-09 18:29:44 +03002090 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
Henrik Boströme574a312020-08-25 10:20:11 +02002091 EXPECT_TRUE(callee->observer()->legacy_renegotiation_needed());
2092 EXPECT_TRUE(callee->observer()->has_negotiation_needed_event());
Eldar Relloead0ec92019-10-21 23:01:31 +03002093 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 2u);
Eldar Rello5ab79e62019-10-09 18:29:44 +03002094 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), absl::nullopt);
2095 EXPECT_EQ(callee->pc()->GetTransceivers()[1]->mid(), absl::nullopt);
2096}
2097
2098TEST_F(PeerConnectionJsepTest, NoRollbackNeeded) {
2099 auto caller = CreatePeerConnection();
2100 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
2101 auto callee = CreatePeerConnection();
2102 callee->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
2103 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
2104 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
2105 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2106 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2107}
2108
Eldar Rello353a7182019-11-25 18:49:44 +02002109TEST_F(PeerConnectionJsepTest, RollbackMultipleStreamChanges) {
2110 auto callee = CreatePeerConnection();
2111 auto caller = CreatePeerConnection();
2112 caller->AddAudioTrack("a_1", {"id_1"});
2113 caller->AddVideoTrack("v_0", {"id_0"}); // Provide an extra stream id.
2114 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2115 EXPECT_TRUE(
2116 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
2117 caller->pc()->GetTransceivers()[0]->sender()->SetStreams({"id_2"});
2118 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2119 caller->pc()->GetTransceivers()[0]->sender()->SetStreams({"id_3"});
2120 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2121 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->receiver()->stream_ids()[0],
2122 "id_3");
2123 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
2124 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->receiver()->stream_ids().size(),
2125 1u);
2126 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->receiver()->stream_ids()[0],
2127 "id_1");
2128}
2129
Eldar Rellod85ea752020-02-19 20:41:07 +02002130TEST_F(PeerConnectionJsepTest, DataChannelImplicitRollback) {
2131 RTCConfiguration config;
2132 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
2133 config.enable_implicit_rollback = true;
2134 auto caller = CreatePeerConnection(config);
2135 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2136 auto callee = CreatePeerConnection(config);
2137 callee->CreateDataChannel("dummy");
2138 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2139 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2140 EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal());
Henrik Boströme574a312020-08-25 10:20:11 +02002141 EXPECT_TRUE(callee->observer()->legacy_renegotiation_needed());
2142 EXPECT_TRUE(callee->observer()->has_negotiation_needed_event());
Eldar Rellod85ea752020-02-19 20:41:07 +02002143 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2144}
2145
2146TEST_F(PeerConnectionJsepTest, RollbackRemoteDataChannelThenAddTransceiver) {
2147 auto caller = CreatePeerConnection();
2148 auto callee = CreatePeerConnection();
2149 caller->CreateDataChannel("dummy");
2150 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2151 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
2152 callee->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2153 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2154}
2155
2156TEST_F(PeerConnectionJsepTest,
2157 RollbackRemoteDataChannelThenAddTransceiverAndDataChannel) {
2158 auto caller = CreatePeerConnection();
2159 auto callee = CreatePeerConnection();
2160 caller->CreateDataChannel("dummy");
2161 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2162 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
2163 callee->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2164 callee->CreateDataChannel("dummy");
2165 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2166}
2167
2168TEST_F(PeerConnectionJsepTest, RollbackRemoteDataChannelThenAddDataChannel) {
2169 auto caller = CreatePeerConnection();
2170 auto callee = CreatePeerConnection();
2171 caller->CreateDataChannel("dummy");
2172 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2173 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
2174 callee->CreateDataChannel("dummy");
2175 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2176}
2177
2178TEST_F(PeerConnectionJsepTest, RollbackRemoteTransceiverThenAddDataChannel) {
2179 auto caller = CreatePeerConnection();
2180 auto callee = CreatePeerConnection();
2181 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2182 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2183 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
2184 callee->CreateDataChannel("dummy");
2185 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2186}
2187
2188TEST_F(PeerConnectionJsepTest,
2189 RollbackRemoteTransceiverThenAddDataChannelAndTransceiver) {
2190 auto caller = CreatePeerConnection();
2191 auto callee = CreatePeerConnection();
2192 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2193 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2194 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
2195 callee->CreateDataChannel("dummy");
2196 callee->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2197 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2198}
2199
Eldar Rellod9ebe012020-03-18 20:41:45 +02002200TEST_F(PeerConnectionJsepTest, RollbackRtpDataChannel) {
2201 RTCConfiguration config;
2202 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
2203 config.enable_rtp_data_channel = true;
2204 auto pc = CreatePeerConnection(config);
2205 pc->CreateDataChannel("dummy");
2206 auto offer = pc->CreateOffer();
2207 EXPECT_TRUE(pc->CreateOfferAndSetAsLocal());
2208 EXPECT_TRUE(pc->SetRemoteDescription(pc->CreateRollback()));
2209 EXPECT_TRUE(pc->SetLocalDescription(std::move(offer)));
2210}
2211
Steve Antondcc3c022017-12-22 16:02:54 -08002212} // namespace webrtc