blob: c3e093617b5a7afb877d0c81a269df434acea57b [file] [log] [blame]
Steve Antondcc3c022017-12-23 00:02:541/*
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 15:06:1811#include <memory>
12
Danil Chapovalov9da25bd2019-06-20 08:19:4213#include "api/task_queue/default_task_queue_factory.h"
Erik Språngceb44952020-09-22 09:36:3514#include "api/transport/field_trial_based_config.h"
Steve Anton10542f22019-01-11 17:11:0015#include "media/engine/webrtc_media_engine.h"
Danil Chapovalov9da25bd2019-06-20 08:19:4216#include "media/engine/webrtc_media_engine_defaults.h"
Steve Anton10542f22019-01-11 17:11:0017#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-23 00:02:5421#ifdef WEBRTC_ANDROID
Steve Anton10542f22019-01-11 17:11:0022#include "pc/test/android_test_initializer.h"
Steve Antondcc3c022017-12-23 00:02:5423#endif
Steve Anton10542f22019-01-11 17:11:0024#include "pc/test/fake_audio_capture_module.h"
Steve Antondcc3c022017-12-23 00:02:5425#include "rtc_base/gunit.h"
Steve Anton10542f22019-01-11 17:11:0026#include "rtc_base/virtual_socket_server.h"
Steve Antondcc3c022017-12-23 00:02:5427#include "test/gmock.h"
Per Kjellander2bca0082020-08-28 07:15:1528#include "test/pc/sctp/fake_sctp_transport.h"
Steve Antondcc3c022017-12-23 00:02:5429
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-23 00:02:5440using ::testing::Combine;
41using ::testing::ElementsAre;
Steve Antonef65ef12018-01-11 01:15:2042using ::testing::UnorderedElementsAre;
Jonas Olssona4d87372019-07-05 17:08:3343using ::testing::Values;
Steve Antondcc3c022017-12-23 00:02:5444
Per Kjellander2bca0082020-08-28 07:15:1545PeerConnectionFactoryDependencies 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 09:36:3551 dependencies.trials = std::make_unique<FieldTrialBasedConfig>();
Per Kjellander2bca0082020-08-28 07:15:1552 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 09:36:3555 media_deps.trials = dependencies.trials.get();
Per Kjellander2bca0082020-08-28 07:15:1556 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-29 00:38:2362
Steve Antondcc3c022017-12-23 00:02:5463class 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-23 00:02:5472 }
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 07:15:1581 rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory =
82 CreateModularPeerConnectionFactory(
83 CreatePeerConnectionFactoryDependencies());
Mirko Bonadei317a1f02019-09-17 15:06:1884 auto observer = std::make_unique<MockPeerConnectionObserver>();
Steve Antonfa2260d2017-12-29 00:38:2385 auto pc = pc_factory->CreatePeerConnection(config, nullptr, nullptr,
86 observer.get());
Steve Antondcc3c022017-12-23 00:02:5487 if (!pc) {
88 return nullptr;
89 }
90
Yves Gerey4e933292018-10-31 14:36:0591 observer->SetPeerConnectionInterface(pc.get());
Mirko Bonadei317a1f02019-09-17 15:06:1892 return std::make_unique<PeerConnectionWrapper>(pc_factory, pc,
93 std::move(observer));
Steve Antondcc3c022017-12-23 00:02:5494 }
95
96 std::unique_ptr<rtc::VirtualSocketServer> vss_;
97 rtc::AutoSocketServerThread main_;
Steve Antondcc3c022017-12-23 00:02:5498};
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-29 00:38:23106
Steve Antondcc3c022017-12-23 00:02:54107 auto offer = caller->CreateOffer();
Steve Antonfa2260d2017-12-29 00:38:23108 ASSERT_EQ(0u, offer->description()->contents().size());
Steve Antondcc3c022017-12-23 00:02:54109}
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-23 00:02:54116
Steve Antonfa2260d2017-12-29 00:38:23117 auto offer = caller->CreateOffer();
Steve Antondcc3c022017-12-23 00:02:54118 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-23 00:02:54128
Steve Antonfa2260d2017-12-29 00:38:23129 auto offer = caller->CreateOffer();
Steve Antondcc3c022017-12-23 00:02:54130 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-29 00:38:23135// 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-23 00:02:54159// 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-23 00:02:54169
Steve Antonfa2260d2017-12-29 00:38:23170 auto offer = caller->CreateOffer();
Steve Antondcc3c022017-12-23 00:02:54171 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-29 00:38:23198
Steve Antondcc3c022017-12-23 00:02:54199 auto offer = caller->CreateOffer();
Steve Antondcc3c022017-12-23 00:02:54200 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 07:54:02209 transceiver->StopInternal();
Steve Antondcc3c022017-12-23 00:02:54210
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-29 00:38:23219
Steve Antondcc3c022017-12-23 00:02:54220 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 21:04:01256
Steve Anton69470252018-02-09 19:43:08257 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, transceivers[0]->media_type());
Steve Antondcc3c022017-12-23 00:02:54258 EXPECT_EQ(caller_audio->mid(), transceivers[0]->mid());
259 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly, transceivers[0]->direction());
Steve Anton1bc97162018-06-25 21:04:01260 EXPECT_EQ(0u, transceivers[0]->sender()->stream_ids().size());
261
Steve Anton69470252018-02-09 19:43:08262 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, transceivers[1]->media_type());
Steve Antondcc3c022017-12-23 00:02:54263 EXPECT_EQ(caller_video->mid(), transceivers[1]->mid());
264 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly, transceivers[1]->direction());
Steve Anton1bc97162018-06-25 21:04:01265 EXPECT_EQ(0u, transceivers[1]->sender()->stream_ids().size());
Steve Antondcc3c022017-12-23 00:02:54266}
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 07:54:02297 caller_audio->SetDirectionWithError(RtpTransceiverDirection::kSendOnly);
Steve Antondcc3c022017-12-23 00:02:54298 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 14:47:43305 EXPECT_EQ(absl::nullopt, transceivers[0]->mid());
Steve Antondcc3c022017-12-23 00:02:54306 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 14:47:43323 EXPECT_EQ(absl::nullopt, transceivers[0]->mid());
Steve Antondcc3c022017-12-23 00:02:54324 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 14:47:43342 EXPECT_EQ(absl::nullopt, transceivers[0]->mid());
Steve Antondcc3c022017-12-23 00:02:54343 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 07:54:02355 callee->pc()->GetTransceivers()[0]->StopInternal();
Steve Antondcc3c022017-12-23 00:02:54356
357 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
358
359 auto transceivers = callee->pc()->GetTransceivers();
Harald Alvestrand936f1af2020-09-22 07:41:50360 ASSERT_EQ(2u, transceivers.size());
361 // The stopped transceiver is removed in SetLocalDescription(answer)
362 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
363 transceivers = callee->pc()->GetTransceivers();
Harald Alvestrand6060df52020-08-11 07:54:02364 ASSERT_EQ(1u, transceivers.size());
365 EXPECT_EQ(caller->pc()->GetTransceivers()[0]->mid(), transceivers[0]->mid());
366 EXPECT_FALSE(transceivers[0]->stopped());
Steve Antondcc3c022017-12-23 00:02:54367}
368
369// Test that audio and video transceivers created on the remote side with
370// AddTrack will all be reused if there is the same number of audio/video tracks
371// in the remote offer. Additionally, this tests that transceivers are
372// successfully matched even if they are in a different order on the remote
373// side.
374TEST_F(PeerConnectionJsepTest, SetRemoteOfferReusesTransceiversOfBothTypes) {
375 auto caller = CreatePeerConnection();
376 caller->AddVideoTrack("v");
377 caller->AddAudioTrack("a");
378 auto callee = CreatePeerConnection();
379 callee->AddAudioTrack("a");
380 callee->AddVideoTrack("v");
381
382 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
383
384 auto caller_transceivers = caller->pc()->GetTransceivers();
385 auto callee_transceivers = callee->pc()->GetTransceivers();
386 ASSERT_EQ(2u, callee_transceivers.size());
387 EXPECT_EQ(caller_transceivers[0]->mid(), callee_transceivers[1]->mid());
388 EXPECT_EQ(caller_transceivers[1]->mid(), callee_transceivers[0]->mid());
389}
390
391// Tests for JSEP initial CreateAnswer.
392
393// Test that the answer to a remote offer creates media sections for each
394// offered media in the same order and with the same mids.
395TEST_F(PeerConnectionJsepTest, CreateAnswerHasSameMidsAsOffer) {
396 auto caller = CreatePeerConnection();
397 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
398 auto second_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
399 auto third_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
Steve Antonfa2260d2017-12-29 00:38:23400 caller->CreateDataChannel("dc");
Steve Antondcc3c022017-12-23 00:02:54401 auto callee = CreatePeerConnection();
402
Steve Antonfa2260d2017-12-29 00:38:23403 auto offer = caller->CreateOffer();
404 const auto* offer_data = cricket::GetFirstDataContent(offer->description());
405 ASSERT_TRUE(
406 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
407 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
Steve Antondcc3c022017-12-23 00:02:54408
409 auto answer = callee->CreateAnswer();
410 auto contents = answer->description()->contents();
Steve Antonfa2260d2017-12-29 00:38:23411 ASSERT_EQ(4u, contents.size());
Steve Antondcc3c022017-12-23 00:02:54412 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, contents[0].media_description()->type());
Steve Antonfa2260d2017-12-29 00:38:23413 EXPECT_EQ(first_transceiver->mid(), contents[0].name);
Steve Antondcc3c022017-12-23 00:02:54414 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, contents[1].media_description()->type());
Steve Antonfa2260d2017-12-29 00:38:23415 EXPECT_EQ(second_transceiver->mid(), contents[1].name);
Steve Antondcc3c022017-12-23 00:02:54416 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, contents[2].media_description()->type());
Steve Antonfa2260d2017-12-29 00:38:23417 EXPECT_EQ(third_transceiver->mid(), contents[2].name);
418 EXPECT_EQ(cricket::MEDIA_TYPE_DATA, contents[3].media_description()->type());
419 EXPECT_EQ(offer_data->name, contents[3].name);
Steve Antondcc3c022017-12-23 00:02:54420}
421
422// Test that an answering media section is marked as rejected if the underlying
423// transceiver has been stopped.
424TEST_F(PeerConnectionJsepTest, CreateAnswerRejectsStoppedTransceiver) {
425 auto caller = CreatePeerConnection();
426 caller->AddAudioTrack("a");
427 auto callee = CreatePeerConnection();
428
429 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
430
Harald Alvestrand6060df52020-08-11 07:54:02431 callee->pc()->GetTransceivers()[0]->StopInternal();
Steve Antondcc3c022017-12-23 00:02:54432
433 auto answer = callee->CreateAnswer();
434 auto contents = answer->description()->contents();
435 ASSERT_EQ(1u, contents.size());
436 EXPECT_TRUE(contents[0].rejected);
437}
438
439// Test that CreateAnswer will generate media sections which will only send or
440// receive if the offer indicates it can do the reciprocating direction.
441// The full matrix is tested more extensively in MediaSession.
442TEST_F(PeerConnectionJsepTest, CreateAnswerNegotiatesDirection) {
443 auto caller = CreatePeerConnection();
444 RtpTransceiverInit init;
445 init.direction = RtpTransceiverDirection::kSendOnly;
446 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init);
447 auto callee = CreatePeerConnection();
448 callee->AddAudioTrack("a");
449
450 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
451
452 auto answer = callee->CreateAnswer();
453 auto contents = answer->description()->contents();
454 ASSERT_EQ(1u, contents.size());
455 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
456 contents[0].media_description()->direction());
457}
458
459// Tests for JSEP SetLocalDescription with a local answer.
460// Note that these test only the additional behaviors not covered by
461// SetLocalDescription with a local offer.
462
463// Test that SetLocalDescription with an answer sets the current_direction
464// property of the transceivers mentioned in the session description.
465TEST_F(PeerConnectionJsepTest, SetLocalAnswerUpdatesCurrentDirection) {
466 auto caller = CreatePeerConnection();
467 auto caller_audio = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
Harald Alvestrand6060df52020-08-11 07:54:02468 caller_audio->SetDirectionWithError(RtpTransceiverDirection::kRecvOnly);
Steve Antondcc3c022017-12-23 00:02:54469 auto callee = CreatePeerConnection();
470 callee->AddAudioTrack("a");
471
472 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
473 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
474
475 auto transceivers = callee->pc()->GetTransceivers();
476 ASSERT_EQ(1u, transceivers.size());
477 // Since the offer was recvonly and the transceiver direction is sendrecv,
478 // the negotiated direction will be sendonly.
479 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
480 transceivers[0]->current_direction());
481}
482
483// Tests for JSEP SetRemoteDescription with a remote answer.
484// Note that these test only the additional behaviors not covered by
485// SetRemoteDescription with a remote offer.
486
487TEST_F(PeerConnectionJsepTest, SetRemoteAnswerUpdatesCurrentDirection) {
488 auto caller = CreatePeerConnection();
489 caller->AddAudioTrack("a");
490 auto callee = CreatePeerConnection();
491 callee->AddAudioTrack("a");
492 auto callee_audio = callee->pc()->GetTransceivers()[0];
Harald Alvestrand6060df52020-08-11 07:54:02493 callee_audio->SetDirectionWithError(RtpTransceiverDirection::kSendOnly);
Steve Antondcc3c022017-12-23 00:02:54494
495 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
496 ASSERT_TRUE(
497 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
498
499 auto transceivers = caller->pc()->GetTransceivers();
500 ASSERT_EQ(1u, transceivers.size());
501 // Since the remote transceiver was set to sendonly, the negotiated direction
502 // in the answer would be sendonly which we apply as recvonly to the local
503 // transceiver.
504 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
505 transceivers[0]->current_direction());
506}
507
508// Tests for multiple round trips.
509
510// Test that setting a transceiver with the inactive direction does not stop it
511// on either the caller or the callee.
512TEST_F(PeerConnectionJsepTest, SettingTransceiverInactiveDoesNotStopIt) {
513 auto caller = CreatePeerConnection();
514 caller->AddAudioTrack("a");
515 auto callee = CreatePeerConnection();
516 callee->AddAudioTrack("a");
Harald Alvestrand6060df52020-08-11 07:54:02517 callee->pc()->GetTransceivers()[0]->SetDirectionWithError(
Steve Antondcc3c022017-12-23 00:02:54518 RtpTransceiverDirection::kInactive);
519
520 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
521 ASSERT_TRUE(
522 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
523
524 EXPECT_FALSE(caller->pc()->GetTransceivers()[0]->stopped());
525 EXPECT_FALSE(callee->pc()->GetTransceivers()[0]->stopped());
526}
527
528// Test that if a transceiver had been associated and later stopped, then a
529// media section is still generated for it and the media section is marked as
530// rejected.
531TEST_F(PeerConnectionJsepTest,
532 ReOfferMediaSectionForAssociatedStoppedTransceiverIsRejected) {
533 auto caller = CreatePeerConnection();
534 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
535 auto callee = CreatePeerConnection();
536
537 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
538 ASSERT_TRUE(
539 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
540
541 ASSERT_TRUE(transceiver->mid());
Harald Alvestrand6060df52020-08-11 07:54:02542 transceiver->StopInternal();
Steve Antondcc3c022017-12-23 00:02:54543
544 auto reoffer = caller->CreateOffer();
545 auto contents = reoffer->description()->contents();
546 ASSERT_EQ(1u, contents.size());
547 EXPECT_TRUE(contents[0].rejected);
548}
549
550// Test that stopping an associated transceiver on the caller side will stop the
551// corresponding transceiver on the remote side when the remote offer is
552// applied.
553TEST_F(PeerConnectionJsepTest,
554 StoppingTransceiverInOfferStopsTransceiverOnRemoteSide) {
555 auto caller = CreatePeerConnection();
556 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
557 auto callee = CreatePeerConnection();
558
559 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
560 ASSERT_TRUE(
561 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
562
Harald Alvestrand6060df52020-08-11 07:54:02563 transceiver->StopInternal();
Steve Antondcc3c022017-12-23 00:02:54564
565 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
566
567 auto transceivers = callee->pc()->GetTransceivers();
Harald Alvestrand936f1af2020-09-22 07:41:50568 EXPECT_EQ(1u, transceivers.size());
569 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
570 transceivers = callee->pc()->GetTransceivers();
Harald Alvestrand6060df52020-08-11 07:54:02571 EXPECT_EQ(0u, transceivers.size());
Steve Antondcc3c022017-12-23 00:02:54572}
573
574// Test that CreateOffer will only generate a recycled media section if the
575// transceiver to be recycled has been seen stopped by the other side first.
576TEST_F(PeerConnectionJsepTest,
577 CreateOfferDoesNotRecycleMediaSectionIfFirstStopped) {
578 auto caller = CreatePeerConnection();
579 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
580 auto callee = CreatePeerConnection();
581
582 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
583 ASSERT_TRUE(
584 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
585
586 auto second_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
Harald Alvestrand6060df52020-08-11 07:54:02587 first_transceiver->StopInternal();
Steve Antondcc3c022017-12-23 00:02:54588
589 auto reoffer = caller->CreateOffer();
590 auto contents = reoffer->description()->contents();
591 ASSERT_EQ(2u, contents.size());
592 EXPECT_TRUE(contents[0].rejected);
593 EXPECT_FALSE(contents[1].rejected);
594}
595
Seth Hampsonae8a90a2018-02-13 23:33:48596// Test that the offer/answer and the transceivers are correctly generated and
597// updated when the media section is recycled after the callee stops a
598// transceiver and sends an answer with a 0 port.
599TEST_F(PeerConnectionJsepTest,
600 RecycleMediaSectionWhenStoppingTransceiverOnAnswerer) {
601 auto caller = CreatePeerConnection();
602 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
603 auto callee = CreatePeerConnection();
604
605 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
Harald Alvestrand936f1af2020-09-22 07:41:50606 std::string first_mid = *first_transceiver->mid();
Harald Alvestrand6060df52020-08-11 07:54:02607 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
608 callee->pc()->GetTransceivers()[0]->StopInternal();
Harald Alvestrand936f1af2020-09-22 07:41:50609 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
Seth Hampsonae8a90a2018-02-13 23:33:48610 ASSERT_TRUE(
611 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
612 EXPECT_TRUE(first_transceiver->stopped());
Harald Alvestrand936f1af2020-09-22 07:41:50613 // First transceivers are dissociated on caller side.
614 ASSERT_EQ(absl::nullopt, first_transceiver->mid());
Harald Alvestrand6060df52020-08-11 07:54:02615 // They are disassociated on callee side.
616 ASSERT_EQ(0u, callee->pc()->GetTransceivers().size());
Seth Hampsonae8a90a2018-02-13 23:33:48617
618 // New offer exchange with new transceivers that recycles the m section
619 // correctly.
620 caller->AddAudioTrack("audio2");
621 callee->AddAudioTrack("audio2");
622 auto offer = caller->CreateOffer();
623 auto offer_contents = offer->description()->contents();
624 std::string second_mid = offer_contents[0].name;
625 ASSERT_EQ(1u, offer_contents.size());
626 EXPECT_FALSE(offer_contents[0].rejected);
627 EXPECT_NE(first_mid, second_mid);
628
629 // Setting the offer on each side will dissociate the first transceivers and
630 // associate the new transceivers.
631 ASSERT_TRUE(
632 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
Danil Chapovalov66cadcc2018-06-19 14:47:43633 EXPECT_EQ(absl::nullopt, first_transceiver->mid());
Harald Alvestrand6060df52020-08-11 07:54:02634 ASSERT_EQ(1u, caller->pc()->GetTransceivers().size());
635 EXPECT_EQ(second_mid, caller->pc()->GetTransceivers()[0]->mid());
Seth Hampsonae8a90a2018-02-13 23:33:48636 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
Harald Alvestrand6060df52020-08-11 07:54:02637 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
638 EXPECT_EQ(second_mid, callee->pc()->GetTransceivers()[0]->mid());
Seth Hampsonae8a90a2018-02-13 23:33:48639
640 // The new answer should also recycle the m section correctly.
641 auto answer = callee->CreateAnswer();
642 auto answer_contents = answer->description()->contents();
643 ASSERT_EQ(1u, answer_contents.size());
644 EXPECT_FALSE(answer_contents[0].rejected);
645 EXPECT_EQ(second_mid, answer_contents[0].name);
646
647 // Finishing the negotiation shouldn't add or dissociate any transceivers.
648 ASSERT_TRUE(
649 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
650 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
651 auto caller_transceivers = caller->pc()->GetTransceivers();
Harald Alvestrand6060df52020-08-11 07:54:02652 ASSERT_EQ(1u, caller_transceivers.size());
653 EXPECT_EQ(second_mid, caller_transceivers[0]->mid());
Seth Hampsonae8a90a2018-02-13 23:33:48654 auto callee_transceivers = callee->pc()->GetTransceivers();
Harald Alvestrand6060df52020-08-11 07:54:02655 ASSERT_EQ(1u, callee_transceivers.size());
656 EXPECT_EQ(second_mid, callee_transceivers[0]->mid());
Seth Hampsonae8a90a2018-02-13 23:33:48657}
658
659// Test that creating/setting a local offer that recycles an m= section is
660// idempotent.
661TEST_F(PeerConnectionJsepTest, CreateOfferRecyclesWhenOfferingTwice) {
662 // Do a negotiation with a port 0 for the media section.
663 auto caller = CreatePeerConnection();
664 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
665 auto callee = CreatePeerConnection();
666 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Harald Alvestrand6060df52020-08-11 07:54:02667 first_transceiver->StopInternal();
Seth Hampsonae8a90a2018-02-13 23:33:48668 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
669 caller->AddAudioTrack("audio2");
670
671 // Create a new offer that recycles the media section and set it as a local
672 // description.
673 auto offer = caller->CreateOffer();
674 auto offer_contents = offer->description()->contents();
675 ASSERT_EQ(1u, offer_contents.size());
676 EXPECT_FALSE(offer_contents[0].rejected);
677 ASSERT_TRUE(caller->SetLocalDescription(std::move(offer)));
Harald Alvestrand6060df52020-08-11 07:54:02678 ASSERT_EQ(1u, caller->pc()->GetTransceivers().size());
679 EXPECT_FALSE(caller->pc()->GetTransceivers()[0]->stopped());
Seth Hampsonae8a90a2018-02-13 23:33:48680 std::string second_mid = offer_contents[0].name;
681
682 // Create another new offer and set the local description again without the
683 // rest of any negotation ocurring.
684 auto second_offer = caller->CreateOffer();
685 auto second_offer_contents = second_offer->description()->contents();
686 ASSERT_EQ(1u, second_offer_contents.size());
687 EXPECT_FALSE(second_offer_contents[0].rejected);
688 // The mid shouldn't change.
689 EXPECT_EQ(second_mid, second_offer_contents[0].name);
690
691 ASSERT_TRUE(caller->SetLocalDescription(std::move(second_offer)));
692 // Make sure that the caller's transceivers are associated correctly.
693 auto caller_transceivers = caller->pc()->GetTransceivers();
Harald Alvestrand6060df52020-08-11 07:54:02694 ASSERT_EQ(1u, caller_transceivers.size());
695 EXPECT_EQ(second_mid, caller_transceivers[0]->mid());
696 EXPECT_FALSE(caller_transceivers[0]->stopped());
Seth Hampsonae8a90a2018-02-13 23:33:48697}
698
Steve Antondcc3c022017-12-23 00:02:54699// Test that the offer/answer and transceivers for both the caller and callee
700// side are generated/updated correctly when recycling an audio/video media
701// section as a media section of either the same or opposite type.
Steve Anton5c72e712018-12-10 22:25:30702// Correct recycling works as follows:
703// - The m= section is re-offered with a new MID value and the new media type.
704// - The previously-associated transceiver is dissociated when the new offer is
705// set as a local description on the offerer or as a remote description on
706// the answerer.
707// - The new transceiver is associated with the new MID value.
Steve Antondcc3c022017-12-23 00:02:54708class RecycleMediaSectionTest
709 : public PeerConnectionJsepTest,
Mirko Bonadei6a489f22019-04-09 13:11:12710 public ::testing::WithParamInterface<
Steve Antondcc3c022017-12-23 00:02:54711 std::tuple<cricket::MediaType, cricket::MediaType>> {
712 protected:
713 RecycleMediaSectionTest() {
714 first_type_ = std::get<0>(GetParam());
715 second_type_ = std::get<1>(GetParam());
716 }
717
718 cricket::MediaType first_type_;
719 cricket::MediaType second_type_;
720};
721
Steve Anton5c72e712018-12-10 22:25:30722// Test that recycling works properly when a new transceiver recycles an m=
723// section that was rejected in both the current local and remote descriptions.
724TEST_P(RecycleMediaSectionTest, CurrentLocalAndCurrentRemoteRejected) {
Steve Antondcc3c022017-12-23 00:02:54725 auto caller = CreatePeerConnection();
726 auto first_transceiver = caller->AddTransceiver(first_type_);
727 auto callee = CreatePeerConnection();
728
729 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
730
731 std::string first_mid = *first_transceiver->mid();
Harald Alvestrand6060df52020-08-11 07:54:02732 first_transceiver->StopInternal();
Steve Antondcc3c022017-12-23 00:02:54733
734 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
735
736 auto second_transceiver = caller->AddTransceiver(second_type_);
737
738 // The offer should reuse the previous media section but allocate a new MID
739 // and change the media type.
740 auto offer = caller->CreateOffer();
741 auto offer_contents = offer->description()->contents();
742 ASSERT_EQ(1u, offer_contents.size());
743 EXPECT_FALSE(offer_contents[0].rejected);
744 EXPECT_EQ(second_type_, offer_contents[0].media_description()->type());
745 std::string second_mid = offer_contents[0].name;
746 EXPECT_NE(first_mid, second_mid);
747
748 // Setting the local offer will dissociate the previous transceiver and set
749 // the MID for the new transceiver.
750 ASSERT_TRUE(
751 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
Danil Chapovalov66cadcc2018-06-19 14:47:43752 EXPECT_EQ(absl::nullopt, first_transceiver->mid());
Steve Antondcc3c022017-12-23 00:02:54753 EXPECT_EQ(second_mid, second_transceiver->mid());
754
755 // Setting the remote offer will dissociate the previous transceiver and
756 // create a new transceiver for the media section.
757 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
758 auto callee_transceivers = callee->pc()->GetTransceivers();
Harald Alvestrand6060df52020-08-11 07:54:02759 ASSERT_EQ(1u, callee_transceivers.size());
760 EXPECT_EQ(second_mid, callee_transceivers[0]->mid());
761 EXPECT_EQ(second_type_, callee_transceivers[0]->media_type());
Steve Antondcc3c022017-12-23 00:02:54762
763 // The answer should have only one media section for the new transceiver.
764 auto answer = callee->CreateAnswer();
765 auto answer_contents = answer->description()->contents();
766 ASSERT_EQ(1u, answer_contents.size());
767 EXPECT_FALSE(answer_contents[0].rejected);
768 EXPECT_EQ(second_mid, answer_contents[0].name);
769 EXPECT_EQ(second_type_, answer_contents[0].media_description()->type());
770
771 // Setting the local answer should succeed.
772 ASSERT_TRUE(
773 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
774
Seth Hampsonae8a90a2018-02-13 23:33:48775 // Setting the remote answer should succeed and not create any new
776 // transceivers.
Steve Antondcc3c022017-12-23 00:02:54777 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
Harald Alvestrand6060df52020-08-11 07:54:02778 ASSERT_EQ(1u, caller->pc()->GetTransceivers().size());
779 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
Steve Antondcc3c022017-12-23 00:02:54780}
781
Steve Anton5c72e712018-12-10 22:25:30782// Test that recycling works properly when a new transceiver recycles an m=
783// section that was rejected in only the current remote description.
784TEST_P(RecycleMediaSectionTest, CurrentRemoteOnlyRejected) {
785 auto caller = CreatePeerConnection();
786 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
787 auto callee = CreatePeerConnection();
788
789 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
790
791 std::string first_mid = *caller_first_transceiver->mid();
792 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
793 auto callee_first_transceiver = callee->pc()->GetTransceivers()[0];
Harald Alvestrand6060df52020-08-11 07:54:02794 callee_first_transceiver->StopInternal();
Steve Anton5c72e712018-12-10 22:25:30795
796 // The answer will have a rejected m= section.
797 ASSERT_TRUE(
798 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
799
800 // The offer should reuse the previous media section but allocate a new MID
801 // and change the media type.
802 auto caller_second_transceiver = caller->AddTransceiver(second_type_);
803 auto offer = caller->CreateOffer();
804 const auto& offer_contents = offer->description()->contents();
805 ASSERT_EQ(1u, offer_contents.size());
806 EXPECT_FALSE(offer_contents[0].rejected);
807 EXPECT_EQ(second_type_, offer_contents[0].media_description()->type());
808 std::string second_mid = offer_contents[0].name;
809 EXPECT_NE(first_mid, second_mid);
810
811 // Setting the local offer will dissociate the previous transceiver and set
812 // the MID for the new transceiver.
813 ASSERT_TRUE(
814 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
815 EXPECT_EQ(absl::nullopt, caller_first_transceiver->mid());
816 EXPECT_EQ(second_mid, caller_second_transceiver->mid());
817
818 // Setting the remote offer will dissociate the previous transceiver and
819 // create a new transceiver for the media section.
820 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
821 auto callee_transceivers = callee->pc()->GetTransceivers();
Harald Alvestrand6060df52020-08-11 07:54:02822 ASSERT_EQ(1u, callee_transceivers.size());
823 EXPECT_EQ(second_mid, callee_transceivers[0]->mid());
824 EXPECT_EQ(second_type_, callee_transceivers[0]->media_type());
Steve Anton5c72e712018-12-10 22:25:30825
826 // The answer should have only one media section for the new transceiver.
827 auto answer = callee->CreateAnswer();
828 auto answer_contents = answer->description()->contents();
829 ASSERT_EQ(1u, answer_contents.size());
830 EXPECT_FALSE(answer_contents[0].rejected);
831 EXPECT_EQ(second_mid, answer_contents[0].name);
832 EXPECT_EQ(second_type_, answer_contents[0].media_description()->type());
833
834 // Setting the local answer should succeed.
835 ASSERT_TRUE(
836 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
837
838 // Setting the remote answer should succeed and not create any new
839 // transceivers.
840 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
Harald Alvestrand6060df52020-08-11 07:54:02841 ASSERT_EQ(1u, caller->pc()->GetTransceivers().size());
842 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
Steve Anton5c72e712018-12-10 22:25:30843}
844
845// Test that recycling works properly when a new transceiver recycles an m=
846// section that was rejected only in the current local description.
847TEST_P(RecycleMediaSectionTest, CurrentLocalOnlyRejected) {
848 auto caller = CreatePeerConnection();
849 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
850 auto callee = CreatePeerConnection();
851
852 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
853
854 std::string first_mid = *caller_first_transceiver->mid();
855 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
856 auto callee_first_transceiver = callee->pc()->GetTransceivers()[0];
Harald Alvestrand6060df52020-08-11 07:54:02857 callee_first_transceiver->StopInternal();
Steve Anton5c72e712018-12-10 22:25:30858
859 // The answer will have a rejected m= section.
860 ASSERT_TRUE(
861 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
862
863 // The offer should reuse the previous media section but allocate a new MID
864 // and change the media type.
865 auto callee_second_transceiver = callee->AddTransceiver(second_type_);
866 auto offer = callee->CreateOffer();
867 const auto& offer_contents = offer->description()->contents();
868 ASSERT_EQ(1u, offer_contents.size());
869 EXPECT_FALSE(offer_contents[0].rejected);
870 EXPECT_EQ(second_type_, offer_contents[0].media_description()->type());
871 std::string second_mid = offer_contents[0].name;
872 EXPECT_NE(first_mid, second_mid);
873
874 // Setting the local offer will dissociate the previous transceiver and set
875 // the MID for the new transceiver.
876 ASSERT_TRUE(
877 callee->SetLocalDescription(CloneSessionDescription(offer.get())));
878 EXPECT_EQ(absl::nullopt, callee_first_transceiver->mid());
879 EXPECT_EQ(second_mid, callee_second_transceiver->mid());
880
881 // Setting the remote offer will dissociate the previous transceiver and
882 // create a new transceiver for the media section.
883 ASSERT_TRUE(caller->SetRemoteDescription(std::move(offer)));
884 auto caller_transceivers = caller->pc()->GetTransceivers();
Harald Alvestrand6060df52020-08-11 07:54:02885 ASSERT_EQ(1u, caller_transceivers.size());
886 EXPECT_EQ(second_mid, caller_transceivers[0]->mid());
887 EXPECT_EQ(second_type_, caller_transceivers[0]->media_type());
Steve Anton5c72e712018-12-10 22:25:30888
889 // The answer should have only one media section for the new transceiver.
890 auto answer = caller->CreateAnswer();
891 auto answer_contents = answer->description()->contents();
892 ASSERT_EQ(1u, answer_contents.size());
893 EXPECT_FALSE(answer_contents[0].rejected);
894 EXPECT_EQ(second_mid, answer_contents[0].name);
895 EXPECT_EQ(second_type_, answer_contents[0].media_description()->type());
896
897 // Setting the local answer should succeed.
898 ASSERT_TRUE(
899 caller->SetLocalDescription(CloneSessionDescription(answer.get())));
900
901 // Setting the remote answer should succeed and not create any new
902 // transceivers.
903 ASSERT_TRUE(callee->SetRemoteDescription(std::move(answer)));
Harald Alvestrand6060df52020-08-11 07:54:02904 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
905 ASSERT_EQ(1u, caller->pc()->GetTransceivers().size());
Steve Anton5c72e712018-12-10 22:25:30906}
907
908// Test that a m= section is *not* recycled if the media section is only
909// rejected in the pending local description and there is no current remote
910// description.
911TEST_P(RecycleMediaSectionTest, PendingLocalRejectedAndNoRemote) {
912 auto caller = CreatePeerConnection();
913 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
914
915 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
916
917 std::string first_mid = *caller_first_transceiver->mid();
Harald Alvestrand6060df52020-08-11 07:54:02918 caller_first_transceiver->StopInternal();
Steve Anton5c72e712018-12-10 22:25:30919
920 // The reoffer will have a rejected m= section.
921 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
922
923 auto caller_second_transceiver = caller->AddTransceiver(second_type_);
924
925 // The reoffer should not recycle the existing m= section since it is not
926 // rejected in either the *current* local or *current* remote description.
927 auto reoffer = caller->CreateOffer();
928 auto reoffer_contents = reoffer->description()->contents();
929 ASSERT_EQ(2u, reoffer_contents.size());
930 EXPECT_TRUE(reoffer_contents[0].rejected);
931 EXPECT_EQ(first_type_, reoffer_contents[0].media_description()->type());
932 EXPECT_EQ(first_mid, reoffer_contents[0].name);
933 EXPECT_FALSE(reoffer_contents[1].rejected);
934 EXPECT_EQ(second_type_, reoffer_contents[1].media_description()->type());
935 std::string second_mid = reoffer_contents[1].name;
936 EXPECT_NE(first_mid, second_mid);
937
938 ASSERT_TRUE(caller->SetLocalDescription(std::move(reoffer)));
939
940 // Both RtpTransceivers are associated.
941 EXPECT_EQ(first_mid, caller_first_transceiver->mid());
942 EXPECT_EQ(second_mid, caller_second_transceiver->mid());
943}
944
945// Test that a m= section is *not* recycled if the media section is only
946// rejected in the pending local description and not rejected in the current
947// remote description.
948TEST_P(RecycleMediaSectionTest, PendingLocalRejectedAndNotRejectedRemote) {
949 auto caller = CreatePeerConnection();
950 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
951 auto callee = CreatePeerConnection();
952
953 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
954
955 std::string first_mid = *caller_first_transceiver->mid();
Harald Alvestrand6060df52020-08-11 07:54:02956 caller_first_transceiver->StopInternal();
Steve Anton5c72e712018-12-10 22:25:30957
958 // The reoffer will have a rejected m= section.
959 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
960
961 auto caller_second_transceiver = caller->AddTransceiver(second_type_);
962
963 // The reoffer should not recycle the existing m= section since it is not
964 // rejected in either the *current* local or *current* remote description.
965 auto reoffer = caller->CreateOffer();
966 auto reoffer_contents = reoffer->description()->contents();
967 ASSERT_EQ(2u, reoffer_contents.size());
968 EXPECT_TRUE(reoffer_contents[0].rejected);
969 EXPECT_EQ(first_type_, reoffer_contents[0].media_description()->type());
970 EXPECT_EQ(first_mid, reoffer_contents[0].name);
971 EXPECT_FALSE(reoffer_contents[1].rejected);
972 EXPECT_EQ(second_type_, reoffer_contents[1].media_description()->type());
973 std::string second_mid = reoffer_contents[1].name;
974 EXPECT_NE(first_mid, second_mid);
975
976 ASSERT_TRUE(caller->SetLocalDescription(std::move(reoffer)));
977
978 // Both RtpTransceivers are associated.
979 EXPECT_EQ(first_mid, caller_first_transceiver->mid());
980 EXPECT_EQ(second_mid, caller_second_transceiver->mid());
981}
982
983// Test that an m= section is *not* recycled if the media section is only
984// rejected in the pending remote description and there is no current local
985// description.
986TEST_P(RecycleMediaSectionTest, PendingRemoteRejectedAndNoLocal) {
987 auto caller = CreatePeerConnection();
988 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
989 auto callee = CreatePeerConnection();
990
991 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
992
993 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
994 auto callee_first_transceiver = callee->pc()->GetTransceivers()[0];
995 std::string first_mid = *callee_first_transceiver->mid();
Harald Alvestrand6060df52020-08-11 07:54:02996 caller_first_transceiver->StopInternal();
Steve Anton5c72e712018-12-10 22:25:30997
998 // The reoffer will have a rejected m= section.
999 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1000
1001 auto callee_second_transceiver = callee->AddTransceiver(second_type_);
1002
1003 // The reoffer should not recycle the existing m= section since it is not
1004 // rejected in either the *current* local or *current* remote description.
1005 auto reoffer = callee->CreateOffer();
1006 auto reoffer_contents = reoffer->description()->contents();
1007 ASSERT_EQ(2u, reoffer_contents.size());
1008 EXPECT_TRUE(reoffer_contents[0].rejected);
1009 EXPECT_EQ(first_type_, reoffer_contents[0].media_description()->type());
1010 EXPECT_EQ(first_mid, reoffer_contents[0].name);
1011 EXPECT_FALSE(reoffer_contents[1].rejected);
1012 EXPECT_EQ(second_type_, reoffer_contents[1].media_description()->type());
1013 std::string second_mid = reoffer_contents[1].name;
1014 EXPECT_NE(first_mid, second_mid);
1015
1016 // Note: Cannot actually set the reoffer since the callee is in the signaling
1017 // state 'have-remote-offer'.
1018}
1019
1020// Test that an m= section is *not* recycled if the media section is only
1021// rejected in the pending remote description and not rejected in the current
1022// local description.
1023TEST_P(RecycleMediaSectionTest, PendingRemoteRejectedAndNotRejectedLocal) {
1024 auto caller = CreatePeerConnection();
1025 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
1026 auto callee = CreatePeerConnection();
1027
1028 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1029
1030 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
1031 auto callee_first_transceiver = callee->pc()->GetTransceivers()[0];
1032 std::string first_mid = *callee_first_transceiver->mid();
Harald Alvestrand6060df52020-08-11 07:54:021033 caller_first_transceiver->StopInternal();
Steve Anton5c72e712018-12-10 22:25:301034
1035 // The reoffer will have a rejected m= section.
1036 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1037
1038 auto callee_second_transceiver = callee->AddTransceiver(second_type_);
1039
1040 // The reoffer should not recycle the existing m= section since it is not
1041 // rejected in either the *current* local or *current* remote description.
1042 auto reoffer = callee->CreateOffer();
1043 auto reoffer_contents = reoffer->description()->contents();
1044 ASSERT_EQ(2u, reoffer_contents.size());
1045 EXPECT_TRUE(reoffer_contents[0].rejected);
1046 EXPECT_EQ(first_type_, reoffer_contents[0].media_description()->type());
1047 EXPECT_EQ(first_mid, reoffer_contents[0].name);
1048 EXPECT_FALSE(reoffer_contents[1].rejected);
1049 EXPECT_EQ(second_type_, reoffer_contents[1].media_description()->type());
1050 std::string second_mid = reoffer_contents[1].name;
1051 EXPECT_NE(first_mid, second_mid);
1052
1053 // Note: Cannot actually set the reoffer since the callee is in the signaling
1054 // state 'have-remote-offer'.
1055}
1056
Steve Antondcc3c022017-12-23 00:02:541057// Test all combinations of audio and video as the first and second media type
1058// for the media section. This is needed for full test coverage because
1059// MediaSession has separate functions for processing audio and video media
1060// sections.
Mirko Bonadeic84f6612019-01-31 11:20:571061INSTANTIATE_TEST_SUITE_P(
Steve Antondcc3c022017-12-23 00:02:541062 PeerConnectionJsepTest,
1063 RecycleMediaSectionTest,
1064 Combine(Values(cricket::MEDIA_TYPE_AUDIO, cricket::MEDIA_TYPE_VIDEO),
1065 Values(cricket::MEDIA_TYPE_AUDIO, cricket::MEDIA_TYPE_VIDEO)));
1066
Steve Antonfa2260d2017-12-29 00:38:231067// Test that a new data channel section will not reuse a recycleable audio or
1068// video media section. Additionally, tests that the new section is added to the
1069// end of the session description.
1070TEST_F(PeerConnectionJsepTest, DataChannelDoesNotRecycleMediaSection) {
1071 auto caller = CreatePeerConnection();
1072 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1073 auto callee = CreatePeerConnection();
1074
1075 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1076
Harald Alvestrand6060df52020-08-11 07:54:021077 transceiver->StopInternal();
Steve Antonfa2260d2017-12-29 00:38:231078
1079 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1080
1081 caller->CreateDataChannel("dc");
1082
1083 auto offer = caller->CreateOffer();
1084 auto offer_contents = offer->description()->contents();
1085 ASSERT_EQ(2u, offer_contents.size());
1086 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO,
1087 offer_contents[0].media_description()->type());
1088 EXPECT_EQ(cricket::MEDIA_TYPE_DATA,
1089 offer_contents[1].media_description()->type());
1090
1091 ASSERT_TRUE(
1092 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
1093 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1094
1095 auto answer = callee->CreateAnswer();
1096 auto answer_contents = answer->description()->contents();
1097 ASSERT_EQ(2u, answer_contents.size());
1098 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO,
1099 answer_contents[0].media_description()->type());
1100 EXPECT_EQ(cricket::MEDIA_TYPE_DATA,
1101 answer_contents[1].media_description()->type());
1102}
1103
1104// Test that if a new track is added to an existing session that has a data,
1105// the new section comes at the end of the new offer, after the existing data
1106// section.
1107TEST_F(PeerConnectionJsepTest, AudioTrackAddedAfterDataSectionInReoffer) {
1108 auto caller = CreatePeerConnection();
1109 caller->CreateDataChannel("dc");
1110 auto callee = CreatePeerConnection();
1111
1112 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1113
1114 caller->AddAudioTrack("a");
1115
1116 auto offer = caller->CreateOffer();
1117 auto contents = offer->description()->contents();
1118 ASSERT_EQ(2u, contents.size());
1119 EXPECT_EQ(cricket::MEDIA_TYPE_DATA, contents[0].media_description()->type());
1120 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, contents[1].media_description()->type());
1121}
1122
Steve Antondcc3c022017-12-23 00:02:541123// Tests for MID properties.
1124
1125static void RenameSection(size_t mline_index,
1126 const std::string& new_mid,
1127 SessionDescriptionInterface* sdesc) {
1128 cricket::SessionDescription* desc = sdesc->description();
1129 std::string old_mid = desc->contents()[mline_index].name;
1130 desc->contents()[mline_index].name = new_mid;
1131 desc->transport_infos()[mline_index].content_name = new_mid;
1132 const cricket::ContentGroup* bundle =
1133 desc->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1134 if (bundle) {
1135 cricket::ContentGroup new_bundle = *bundle;
1136 if (new_bundle.RemoveContentName(old_mid)) {
1137 new_bundle.AddContentName(new_mid);
1138 }
1139 desc->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1140 desc->AddGroup(new_bundle);
1141 }
1142}
1143
1144// Test that two PeerConnections can have a successful offer/answer exchange if
1145// the MIDs are changed from the defaults.
1146TEST_F(PeerConnectionJsepTest, OfferAnswerWithChangedMids) {
1147 constexpr char kFirstMid[] = "nondefaultmid";
1148 constexpr char kSecondMid[] = "randommid";
1149
1150 auto caller = CreatePeerConnection();
1151 caller->AddAudioTrack("a");
1152 caller->AddAudioTrack("b");
1153 auto callee = CreatePeerConnection();
1154
1155 auto offer = caller->CreateOffer();
1156 RenameSection(0, kFirstMid, offer.get());
1157 RenameSection(1, kSecondMid, offer.get());
1158
1159 ASSERT_TRUE(
1160 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
1161 auto caller_transceivers = caller->pc()->GetTransceivers();
1162 EXPECT_EQ(kFirstMid, caller_transceivers[0]->mid());
1163 EXPECT_EQ(kSecondMid, caller_transceivers[1]->mid());
1164
1165 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1166 auto callee_transceivers = callee->pc()->GetTransceivers();
1167 EXPECT_EQ(kFirstMid, callee_transceivers[0]->mid());
1168 EXPECT_EQ(kSecondMid, callee_transceivers[1]->mid());
1169
1170 auto answer = callee->CreateAnswer();
1171 auto answer_contents = answer->description()->contents();
1172 EXPECT_EQ(kFirstMid, answer_contents[0].name);
1173 EXPECT_EQ(kSecondMid, answer_contents[1].name);
1174
1175 ASSERT_TRUE(
1176 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
1177 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
1178}
1179
1180// Test that CreateOffer will generate a MID that is not already used if the
1181// default it would have picked is already taken. This is tested by using a
1182// third PeerConnection to determine what the default would be for the second
1183// media section then setting that as the first media section's MID.
1184TEST_F(PeerConnectionJsepTest, CreateOfferGeneratesUniqueMidIfAlreadyTaken) {
1185 // First, find what the default MID is for the second media section.
1186 auto pc = CreatePeerConnection();
1187 pc->AddAudioTrack("a");
1188 pc->AddAudioTrack("b");
1189 auto default_offer = pc->CreateOffer();
1190 std::string default_second_mid =
1191 default_offer->description()->contents()[1].name;
1192
1193 // Now, do an offer/answer with one track which has the MID set to the default
1194 // second MID.
1195 auto caller = CreatePeerConnection();
1196 caller->AddAudioTrack("a");
1197 auto callee = CreatePeerConnection();
1198
1199 auto offer = caller->CreateOffer();
1200 RenameSection(0, default_second_mid, offer.get());
1201
1202 ASSERT_TRUE(
1203 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
1204 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1205 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1206
1207 // Add a second track and ensure that the MID is different.
1208 caller->AddAudioTrack("b");
1209
1210 auto reoffer = caller->CreateOffer();
1211 auto reoffer_contents = reoffer->description()->contents();
1212 EXPECT_EQ(default_second_mid, reoffer_contents[0].name);
1213 EXPECT_NE(reoffer_contents[0].name, reoffer_contents[1].name);
1214}
1215
Steve Antonfa2260d2017-12-29 00:38:231216// Test that if an audio or video section has the default data section MID, then
1217// CreateOffer will generate a unique MID for the newly added data section.
1218TEST_F(PeerConnectionJsepTest,
1219 CreateOfferGeneratesUniqueMidForDataSectionIfAlreadyTaken) {
1220 // First, find what the default MID is for the data channel.
1221 auto pc = CreatePeerConnection();
1222 pc->CreateDataChannel("dc");
1223 auto default_offer = pc->CreateOffer();
1224 std::string default_data_mid =
1225 default_offer->description()->contents()[0].name;
1226
1227 // Now do an offer/answer with one audio track which has a MID set to the
1228 // default data MID.
1229 auto caller = CreatePeerConnection();
1230 caller->AddAudioTrack("a");
1231 auto callee = CreatePeerConnection();
1232
1233 auto offer = caller->CreateOffer();
1234 RenameSection(0, default_data_mid, offer.get());
1235
1236 ASSERT_TRUE(
1237 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
1238 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1239 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1240
1241 // Add a data channel and ensure that the MID is different.
1242 caller->CreateDataChannel("dc");
1243
1244 auto reoffer = caller->CreateOffer();
1245 auto reoffer_contents = reoffer->description()->contents();
1246 EXPECT_EQ(default_data_mid, reoffer_contents[0].name);
1247 EXPECT_NE(reoffer_contents[0].name, reoffer_contents[1].name);
1248}
1249
Steve Antondcc3c022017-12-23 00:02:541250// Test that a reoffer initiated by the callee adds a new track to the caller.
1251TEST_F(PeerConnectionJsepTest, CalleeDoesReoffer) {
1252 auto caller = CreatePeerConnection();
1253 caller->AddAudioTrack("a");
1254 auto callee = CreatePeerConnection();
1255 callee->AddAudioTrack("a");
1256 callee->AddVideoTrack("v");
1257
1258 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1259
1260 EXPECT_EQ(1u, caller->pc()->GetTransceivers().size());
1261 EXPECT_EQ(2u, callee->pc()->GetTransceivers().size());
1262
1263 ASSERT_TRUE(callee->ExchangeOfferAnswerWith(caller.get()));
1264
1265 EXPECT_EQ(2u, caller->pc()->GetTransceivers().size());
1266 EXPECT_EQ(2u, callee->pc()->GetTransceivers().size());
1267}
1268
Steve Anton02ee47c2018-01-11 00:26:061269// Tests for MSID properties.
1270
1271// Test that adding a track with AddTrack results in an offer that signals the
1272// track's ID.
1273TEST_F(PeerConnectionJsepTest, AddingTrackWithAddTrackSpecifiesTrackId) {
1274 const std::string kTrackId = "audio_track";
1275
1276 auto caller = CreatePeerConnection();
1277 caller->AddAudioTrack(kTrackId);
1278
1279 auto offer = caller->CreateOffer();
1280 auto contents = offer->description()->contents();
1281 ASSERT_EQ(1u, contents.size());
1282 auto streams = contents[0].media_description()->streams();
1283 ASSERT_EQ(1u, streams.size());
1284 EXPECT_EQ(kTrackId, streams[0].id);
1285}
1286
1287// Test that adding a track by calling AddTransceiver then SetTrack results in
1288// an offer that does not signal the track's ID and signals a random ID.
1289TEST_F(PeerConnectionJsepTest,
1290 AddingTrackWithAddTransceiverSpecifiesRandomTrackId) {
1291 const std::string kTrackId = "audio_track";
1292
1293 auto caller = CreatePeerConnection();
1294 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1295 transceiver->sender()->SetTrack(caller->CreateAudioTrack(kTrackId));
1296
1297 auto offer = caller->CreateOffer();
1298 auto contents = offer->description()->contents();
1299 ASSERT_EQ(1u, contents.size());
1300 auto streams = contents[0].media_description()->streams();
1301 ASSERT_EQ(1u, streams.size());
1302 EXPECT_NE(kTrackId, streams[0].id);
1303}
1304
Steve Anton5f94aa22018-02-01 18:58:301305// Test that if the transceiver is recvonly or inactive, then no MSID
1306// information is included in the offer.
1307TEST_F(PeerConnectionJsepTest, NoMsidInOfferIfTransceiverDirectionHasNoSend) {
1308 auto caller = CreatePeerConnection();
1309
1310 RtpTransceiverInit init_recvonly;
1311 init_recvonly.direction = RtpTransceiverDirection::kRecvOnly;
1312 ASSERT_TRUE(caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init_recvonly));
1313
1314 RtpTransceiverInit init_inactive;
1315 init_inactive.direction = RtpTransceiverDirection::kInactive;
1316 ASSERT_TRUE(caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init_inactive));
1317
1318 auto offer = caller->CreateOffer();
1319 auto contents = offer->description()->contents();
1320 ASSERT_EQ(2u, contents.size());
1321 // MSID is specified in the first stream, so no streams means no MSID.
1322 EXPECT_EQ(0u, contents[0].media_description()->streams().size());
1323 EXPECT_EQ(0u, contents[1].media_description()->streams().size());
1324}
1325
1326// Test that if an answer negotiates transceiver directions of recvonly or
1327// inactive, then no MSID information is included in the answer.
1328TEST_F(PeerConnectionJsepTest, NoMsidInAnswerIfNoRespondingTracks) {
1329 auto caller = CreatePeerConnection();
1330 auto callee = CreatePeerConnection();
1331
1332 // recvonly transceiver will get negotiated to inactive since the callee has
1333 // no tracks to send in response.
1334 RtpTransceiverInit init_recvonly;
1335 init_recvonly.direction = RtpTransceiverDirection::kRecvOnly;
1336 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init_recvonly);
1337
1338 // sendrecv transceiver will get negotiated to recvonly since the callee has
1339 // no tracks to send in response.
1340 RtpTransceiverInit init_sendrecv;
1341 init_sendrecv.direction = RtpTransceiverDirection::kSendRecv;
1342 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init_sendrecv);
1343
1344 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1345
1346 auto answer = callee->CreateAnswer();
1347 auto contents = answer->description()->contents();
1348 ASSERT_EQ(2u, contents.size());
1349 // MSID is specified in the first stream, so no streams means no MSID.
1350 EXPECT_EQ(0u, contents[0].media_description()->streams().size());
1351 EXPECT_EQ(0u, contents[1].media_description()->streams().size());
1352}
1353
1354// Test that the MSID is included even if the transceiver direction has changed
1355// to inactive if the transceiver had previously sent media.
1356TEST_F(PeerConnectionJsepTest, IncludeMsidEvenIfDirectionHasChanged) {
1357 auto caller = CreatePeerConnection();
1358 caller->AddAudioTrack("audio");
1359 auto callee = CreatePeerConnection();
1360 callee->AddAudioTrack("audio");
1361
1362 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1363
Harald Alvestrand6060df52020-08-11 07:54:021364 caller->pc()->GetTransceivers()[0]->SetDirectionWithError(
Steve Anton5f94aa22018-02-01 18:58:301365 RtpTransceiverDirection::kInactive);
1366
1367 // The transceiver direction on both sides will turn to inactive.
1368 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1369
1370 auto* offer = callee->pc()->remote_description();
1371 auto offer_contents = offer->description()->contents();
1372 ASSERT_EQ(1u, offer_contents.size());
1373 // MSID is specified in the first stream. If it is present, assume that MSID
1374 // is there.
1375 EXPECT_EQ(1u, offer_contents[0].media_description()->streams().size());
1376
1377 auto* answer = caller->pc()->remote_description();
1378 auto answer_contents = answer->description()->contents();
1379 ASSERT_EQ(1u, answer_contents.size());
1380 EXPECT_EQ(1u, answer_contents[0].media_description()->streams().size());
1381}
1382
1383// Test that stopping a RtpTransceiver will cause future offers to not include
1384// any MSID information for that section.
1385TEST_F(PeerConnectionJsepTest, RemoveMsidIfTransceiverStopped) {
1386 auto caller = CreatePeerConnection();
1387 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1388 auto callee = CreatePeerConnection();
1389
1390 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1391
Harald Alvestrand6060df52020-08-11 07:54:021392 transceiver->StopInternal();
Steve Anton5f94aa22018-02-01 18:58:301393
1394 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1395
1396 auto* offer = callee->pc()->remote_description();
1397 auto offer_contents = offer->description()->contents();
1398 ASSERT_EQ(1u, offer_contents.size());
1399 // MSID is specified in the first stream, so no streams means no MSID.
1400 EXPECT_EQ(0u, offer_contents[0].media_description()->streams().size());
1401}
1402
Steve Anton02ee47c2018-01-11 00:26:061403// Test that the callee RtpReceiver created by a call to SetRemoteDescription
1404// has its ID set to the signaled track ID.
1405TEST_F(PeerConnectionJsepTest,
1406 RtpReceiverCreatedBySetRemoteDescriptionHasSignaledTrackId) {
1407 const std::string kTrackId = "audio_track";
1408
1409 auto caller = CreatePeerConnection();
1410 auto callee = CreatePeerConnection();
1411 caller->AddAudioTrack(kTrackId);
1412
1413 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1414
1415 ASSERT_EQ(1u, callee->pc()->GetReceivers().size());
1416 auto receiver = callee->pc()->GetReceivers()[0];
1417 EXPECT_EQ(kTrackId, receiver->id());
1418}
1419
1420// Test that if the callee RtpReceiver is reused by a call to
1421// SetRemoteDescription, its ID does not change.
1422TEST_F(PeerConnectionJsepTest,
1423 RtpReceiverCreatedBeforeSetRemoteDescriptionKeepsId) {
1424 const std::string kTrackId = "audio_track";
1425
1426 auto caller = CreatePeerConnection();
1427 auto callee = CreatePeerConnection();
1428 caller->AddAudioTrack(kTrackId);
1429 callee->AddAudioTrack("dummy_track");
1430
1431 ASSERT_EQ(1u, callee->pc()->GetReceivers().size());
1432 auto receiver = callee->pc()->GetReceivers()[0];
1433 std::string receiver_id = receiver->id();
1434
1435 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1436
1437 EXPECT_EQ(receiver_id, receiver->id());
1438}
1439
Steve Antonef65ef12018-01-11 01:15:201440// Test that setting a remote offer with one track that has no streams fires off
1441// the correct OnAddTrack event.
1442TEST_F(PeerConnectionJsepTest,
1443 SetRemoteOfferWithOneTrackNoStreamFiresOnAddTrack) {
1444 const std::string kTrackLabel = "audio_track";
1445
1446 auto caller = CreatePeerConnection();
1447 auto callee = CreatePeerConnection();
1448 ASSERT_TRUE(caller->AddAudioTrack(kTrackLabel));
1449
1450 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1451
Seth Hampson5b4f0752018-04-02 23:31:361452 const auto& track_events = callee->observer()->add_track_events_;
1453 ASSERT_EQ(1u, track_events.size());
1454 const auto& event = track_events[0];
1455 EXPECT_EQ(kTrackLabel, event.receiver->track()->id());
1456 EXPECT_EQ(0u, event.streams.size());
Steve Antonef65ef12018-01-11 01:15:201457}
1458
1459// Test that setting a remote offer with one track that has one stream fires off
1460// the correct OnAddTrack event.
1461TEST_F(PeerConnectionJsepTest,
1462 SetRemoteOfferWithOneTrackOneStreamFiresOnAddTrack) {
1463 const std::string kTrackLabel = "audio_track";
Seth Hampson845e8782018-03-02 19:34:101464 const std::string kStreamId = "audio_stream";
Steve Antonef65ef12018-01-11 01:15:201465
1466 auto caller = CreatePeerConnection();
1467 auto callee = CreatePeerConnection();
Seth Hampson845e8782018-03-02 19:34:101468 ASSERT_TRUE(caller->AddAudioTrack(kTrackLabel, {kStreamId}));
Steve Antonef65ef12018-01-11 01:15:201469
1470 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1471
1472 const auto& track_events = callee->observer()->add_track_events_;
1473 ASSERT_EQ(1u, track_events.size());
1474 const auto& event = track_events[0];
1475 ASSERT_EQ(1u, event.streams.size());
1476 auto stream = event.streams[0];
Seth Hampson13b8bad2018-03-13 23:05:281477 EXPECT_EQ(kStreamId, stream->id());
Steve Antonef65ef12018-01-11 01:15:201478 EXPECT_THAT(track_events[0].snapshotted_stream_tracks.at(stream),
1479 ElementsAre(event.receiver->track()));
1480 EXPECT_EQ(event.receiver->streams(), track_events[0].streams);
1481}
1482
1483// Test that setting a remote offer with two tracks that share the same stream
1484// fires off two OnAddTrack events, both with the same stream that has both
1485// tracks present at the time of firing. This is to ensure that track events are
1486// not fired until SetRemoteDescription has finished processing all the media
1487// sections.
1488TEST_F(PeerConnectionJsepTest,
1489 SetRemoteOfferWithTwoTracksSameStreamFiresOnAddTrack) {
1490 const std::string kTrack1Label = "audio_track1";
1491 const std::string kTrack2Label = "audio_track2";
Seth Hampson845e8782018-03-02 19:34:101492 const std::string kSharedStreamId = "stream";
Steve Antonef65ef12018-01-11 01:15:201493
1494 auto caller = CreatePeerConnection();
1495 auto callee = CreatePeerConnection();
Seth Hampson845e8782018-03-02 19:34:101496 ASSERT_TRUE(caller->AddAudioTrack(kTrack1Label, {kSharedStreamId}));
1497 ASSERT_TRUE(caller->AddAudioTrack(kTrack2Label, {kSharedStreamId}));
Steve Antonef65ef12018-01-11 01:15:201498
1499 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1500
1501 const auto& track_events = callee->observer()->add_track_events_;
1502 ASSERT_EQ(2u, track_events.size());
1503 const auto& event1 = track_events[0];
1504 const auto& event2 = track_events[1];
1505 ASSERT_EQ(1u, event1.streams.size());
1506 auto stream = event1.streams[0];
1507 ASSERT_THAT(event2.streams, ElementsAre(stream));
1508 auto track1 = event1.receiver->track();
1509 auto track2 = event2.receiver->track();
1510 EXPECT_THAT(event1.snapshotted_stream_tracks.at(stream),
1511 UnorderedElementsAre(track1, track2));
1512 EXPECT_THAT(event2.snapshotted_stream_tracks.at(stream),
1513 UnorderedElementsAre(track1, track2));
1514}
1515
Seth Hampson5b4f0752018-04-02 23:31:361516// Test that setting a remote offer with one track that has two streams fires
1517// off the correct OnAddTrack event.
1518TEST_F(PeerConnectionJsepTest,
1519 SetRemoteOfferWithOneTrackTwoStreamFiresOnAddTrack) {
1520 const std::string kTrackLabel = "audio_track";
1521 const std::string kStreamId1 = "audio_stream1";
1522 const std::string kStreamId2 = "audio_stream2";
1523
1524 auto caller = CreatePeerConnection();
1525 auto callee = CreatePeerConnection();
1526 ASSERT_TRUE(caller->AddAudioTrack(kTrackLabel, {kStreamId1, kStreamId2}));
1527
1528 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1529
1530 const auto& track_events = callee->observer()->add_track_events_;
1531 ASSERT_EQ(1u, track_events.size());
1532 const auto& event = track_events[0];
1533 ASSERT_EQ(2u, event.streams.size());
1534 EXPECT_EQ(kStreamId1, event.streams[0]->id());
1535 EXPECT_EQ(kStreamId2, event.streams[1]->id());
1536}
Steve Antonef65ef12018-01-11 01:15:201537
Steve Anton54b84072018-02-20 23:19:521538// Test that if an RtpTransceiver with a current_direction set is stopped, then
1539// current_direction is changed to null.
1540TEST_F(PeerConnectionJsepTest, CurrentDirectionResetWhenRtpTransceiverStopped) {
1541 auto caller = CreatePeerConnection();
1542 auto callee = CreatePeerConnection();
1543
1544 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1545
1546 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1547
1548 ASSERT_TRUE(transceiver->current_direction());
Harald Alvestrand6060df52020-08-11 07:54:021549 transceiver->StopInternal();
1550 EXPECT_EQ(transceiver->current_direction(),
1551 RtpTransceiverDirection::kStopped);
Steve Anton54b84072018-02-20 23:19:521552}
1553
Steve Antonba42e992018-04-09 21:10:011554// Test that you can't set an answer on a PeerConnection before setting the
1555// offer.
Harald Alvestrand5081c0c2018-03-09 14:18:031556TEST_F(PeerConnectionJsepTest, AnswerBeforeOfferFails) {
1557 auto caller = CreatePeerConnection();
1558 auto callee = CreatePeerConnection();
Harald Alvestrand5081c0c2018-03-09 14:18:031559 caller->AddAudioTrack("audio");
Steve Antonba42e992018-04-09 21:10:011560
1561 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1562
1563 RTCError error;
1564 ASSERT_FALSE(caller->SetRemoteDescription(callee->CreateAnswer(), &error));
1565 EXPECT_EQ(RTCErrorType::INVALID_STATE, error.type());
1566}
1567
1568// Test that a Unified Plan PeerConnection fails to set a Plan B offer if it has
1569// two video tracks.
1570TEST_F(PeerConnectionJsepTest, TwoVideoPlanBToUnifiedPlanFails) {
1571 RTCConfiguration config_planb;
1572 config_planb.sdp_semantics = SdpSemantics::kPlanB;
1573 auto caller = CreatePeerConnection(config_planb);
1574 auto callee = CreatePeerConnection();
1575 caller->AddVideoTrack("video1");
1576 caller->AddVideoTrack("video2");
1577
1578 RTCError error;
1579 ASSERT_FALSE(callee->SetRemoteDescription(caller->CreateOffer(), &error));
1580 EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, error.type());
1581}
1582
1583// Test that a Unified Plan PeerConnection fails to set a Plan B answer if it
1584// has two video tracks.
1585TEST_F(PeerConnectionJsepTest, OneVideoUnifiedPlanToTwoVideoPlanBFails) {
1586 auto caller = CreatePeerConnection();
1587 RTCConfiguration config_planb;
1588 config_planb.sdp_semantics = SdpSemantics::kPlanB;
1589 auto callee = CreatePeerConnection(config_planb);
1590 caller->AddVideoTrack("video");
1591 callee->AddVideoTrack("video1");
1592 callee->AddVideoTrack("video2");
1593
1594 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1595
1596 RTCError error;
1597 ASSERT_FALSE(caller->SetRemoteDescription(caller->CreateAnswer(), &error));
1598 EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, error.type());
Harald Alvestrand5081c0c2018-03-09 14:18:031599}
1600
Steve Anton06817cd2018-12-18 23:55:301601// Removes the RTP header extension associated with the given URI from the media
1602// description.
1603static void RemoveRtpHeaderExtensionByUri(
1604 MediaContentDescription* media_description,
1605 absl::string_view uri) {
1606 std::vector<RtpExtension> header_extensions =
1607 media_description->rtp_header_extensions();
1608 header_extensions.erase(std::remove_if(
1609 header_extensions.begin(), header_extensions.end(),
1610 [uri](const RtpExtension& extension) { return extension.uri == uri; }));
1611 media_description->set_rtp_header_extensions(header_extensions);
1612}
1613
1614// Transforms a session description to emulate a legacy endpoint which does not
1615// support a=mid, BUNDLE, and the MID header extension.
1616static void ClearMids(SessionDescriptionInterface* sdesc) {
1617 cricket::SessionDescription* desc = sdesc->description();
1618 desc->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1619 cricket::ContentInfo* audio_content = cricket::GetFirstAudioContent(desc);
1620 if (audio_content) {
1621 desc->GetTransportInfoByName(audio_content->name)->content_name = "";
1622 audio_content->name = "";
1623 RemoveRtpHeaderExtensionByUri(audio_content->media_description(),
1624 RtpExtension::kMidUri);
1625 }
1626 cricket::ContentInfo* video_content = cricket::GetFirstVideoContent(desc);
1627 if (video_content) {
1628 desc->GetTransportInfoByName(video_content->name)->content_name = "";
1629 video_content->name = "";
1630 RemoveRtpHeaderExtensionByUri(video_content->media_description(),
1631 RtpExtension::kMidUri);
1632 }
1633}
1634
1635// Test that negotiation works with legacy endpoints which do not support a=mid.
1636TEST_F(PeerConnectionJsepTest, LegacyNoMidAudioOnlyOffer) {
1637 auto caller = CreatePeerConnection();
1638 caller->AddAudioTrack("audio");
1639 auto callee = CreatePeerConnection();
1640 callee->AddAudioTrack("audio");
1641
1642 auto offer = caller->CreateOffer();
1643 ClearMids(offer.get());
1644
1645 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1646 EXPECT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1647}
1648TEST_F(PeerConnectionJsepTest, LegacyNoMidAudioVideoOffer) {
1649 auto caller = CreatePeerConnection();
1650 caller->AddAudioTrack("audio");
1651 caller->AddVideoTrack("video");
1652 auto callee = CreatePeerConnection();
1653 callee->AddAudioTrack("audio");
1654 callee->AddVideoTrack("video");
1655
1656 auto offer = caller->CreateOffer();
1657 ClearMids(offer.get());
1658
1659 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1660 EXPECT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1661}
1662TEST_F(PeerConnectionJsepTest, LegacyNoMidAudioOnlyAnswer) {
1663 auto caller = CreatePeerConnection();
1664 caller->AddAudioTrack("audio");
1665 auto callee = CreatePeerConnection();
1666 callee->AddAudioTrack("audio");
1667
1668 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1669
1670 auto answer = callee->CreateAnswer();
1671 ClearMids(answer.get());
1672
1673 EXPECT_TRUE(caller->SetRemoteDescription(std::move(answer)));
1674}
1675TEST_F(PeerConnectionJsepTest, LegacyNoMidAudioVideoAnswer) {
1676 auto caller = CreatePeerConnection();
1677 caller->AddAudioTrack("audio");
1678 caller->AddVideoTrack("video");
1679 auto callee = CreatePeerConnection();
1680 callee->AddAudioTrack("audio");
1681 callee->AddVideoTrack("video");
1682
1683 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1684
1685 auto answer = callee->CreateAnswer();
1686 ClearMids(answer.get());
1687
1688 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
1689}
1690
Steve Antond7180cc2019-02-07 18:44:531691// Test that negotiation works with legacy endpoints which do not support a=mid
1692// when setting two remote descriptions without setting a local description in
1693// between.
1694TEST_F(PeerConnectionJsepTest, LegacyNoMidTwoRemoteOffers) {
1695 auto caller = CreatePeerConnection();
1696 caller->AddAudioTrack("audio");
1697 auto callee = CreatePeerConnection();
1698 callee->AddAudioTrack("audio");
1699
1700 auto offer = caller->CreateOffer();
1701 ClearMids(offer.get());
1702
1703 ASSERT_TRUE(
1704 callee->SetRemoteDescription(CloneSessionDescription(offer.get())));
1705 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1706 EXPECT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1707}
1708
Steve Antonceac0152018-12-19 19:32:201709// Test that SetLocalDescription fails if a=mid lines are missing.
1710TEST_F(PeerConnectionJsepTest, SetLocalDescriptionFailsMissingMid) {
1711 auto caller = CreatePeerConnection();
1712 caller->AddAudioTrack("audio");
1713
1714 auto offer = caller->CreateOffer();
1715 ClearMids(offer.get());
1716
1717 std::string error;
1718 ASSERT_FALSE(caller->SetLocalDescription(std::move(offer), &error));
1719 EXPECT_EQ(
1720 "Failed to set local offer sdp: A media section is missing a MID "
1721 "attribute.",
1722 error);
1723}
1724
Eldar Rello5ab79e62019-10-09 15:29:441725TEST_F(PeerConnectionJsepTest, RollbackSupportedInUnifiedPlan) {
1726 RTCConfiguration config;
1727 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
1728 config.enable_implicit_rollback = true;
1729 auto caller = CreatePeerConnection(config);
1730 auto callee = CreatePeerConnection(config);
1731 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
1732 EXPECT_TRUE(caller->SetLocalDescription(caller->CreateRollback()));
1733 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
1734 EXPECT_TRUE(caller->SetRemoteDescription(caller->CreateRollback()));
1735 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
1736 EXPECT_TRUE(caller->SetRemoteDescription(callee->CreateOffer()));
1737}
1738
1739TEST_F(PeerConnectionJsepTest, RollbackNotSupportedInPlanB) {
1740 RTCConfiguration config;
1741 config.sdp_semantics = SdpSemantics::kPlanB;
1742 config.enable_implicit_rollback = true;
1743 auto caller = CreatePeerConnection(config);
1744 auto callee = CreatePeerConnection(config);
1745 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
1746 EXPECT_FALSE(caller->SetLocalDescription(caller->CreateRollback()));
1747 EXPECT_FALSE(caller->SetRemoteDescription(caller->CreateRollback()));
1748 EXPECT_FALSE(caller->SetRemoteDescription(callee->CreateOffer()));
1749}
1750
1751TEST_F(PeerConnectionJsepTest, RollbackFailsInStableState) {
1752 auto caller = CreatePeerConnection();
1753 EXPECT_FALSE(caller->SetLocalDescription(caller->CreateRollback()));
1754 EXPECT_FALSE(caller->SetRemoteDescription(caller->CreateRollback()));
1755}
1756
1757TEST_F(PeerConnectionJsepTest, RollbackToStableStateAndClearLocalOffer) {
1758 auto caller = CreatePeerConnection();
1759 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
1760 EXPECT_TRUE(caller->SetLocalDescription(caller->CreateRollback()));
1761 EXPECT_EQ(caller->signaling_state(), PeerConnectionInterface::kStable);
1762 EXPECT_EQ(caller->pc()->pending_local_description(), nullptr);
1763
1764 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
1765 EXPECT_TRUE(caller->SetRemoteDescription(caller->CreateRollback()));
1766 EXPECT_EQ(caller->signaling_state(), PeerConnectionInterface::kStable);
1767 EXPECT_EQ(caller->pc()->pending_local_description(), nullptr);
1768}
1769
1770TEST_F(PeerConnectionJsepTest, RollbackToStableStateAndClearRemoteOffer) {
1771 auto caller = CreatePeerConnection();
1772 auto callee = CreatePeerConnection();
1773 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1774 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
1775 EXPECT_EQ(callee->signaling_state(), PeerConnectionInterface::kStable);
1776 EXPECT_EQ(callee->pc()->pending_remote_description(), nullptr);
1777
1778 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1779 EXPECT_TRUE(callee->SetLocalDescription(caller->CreateRollback()));
1780 EXPECT_EQ(callee->signaling_state(), PeerConnectionInterface::kStable);
1781 EXPECT_EQ(callee->pc()->pending_remote_description(), nullptr);
1782}
1783
Eldar Relloead0ec92019-10-21 20:01:311784TEST_F(PeerConnectionJsepTest, RollbackImplicitly) {
Eldar Rello5ab79e62019-10-09 15:29:441785 RTCConfiguration config;
1786 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
1787 config.enable_implicit_rollback = true;
1788 auto caller = CreatePeerConnection(config);
1789 auto callee = CreatePeerConnection(config);
1790 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
1791 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1792 EXPECT_EQ(callee->signaling_state(),
1793 PeerConnectionInterface::kHaveRemoteOffer);
Eldar Relloead0ec92019-10-21 20:01:311794 EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal());
Henrik Boströme574a312020-08-25 08:20:111795 EXPECT_FALSE(callee->observer()->legacy_renegotiation_needed());
1796 EXPECT_FALSE(callee->observer()->has_negotiation_needed_event());
Eldar Rello5ab79e62019-10-09 15:29:441797}
1798
Eldar Relloead0ec92019-10-21 20:01:311799TEST_F(PeerConnectionJsepTest, RollbackImplicitlyNegotatiationNotNeeded) {
1800 RTCConfiguration config;
1801 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
1802 config.enable_implicit_rollback = true;
1803 auto caller = CreatePeerConnection(config);
1804 auto callee = CreatePeerConnection(config);
1805 caller->AddAudioTrack("a");
1806 callee->AddAudioTrack("b");
1807 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
Henrik Boströme574a312020-08-25 08:20:111808 callee->observer()->clear_legacy_renegotiation_needed();
1809 callee->observer()->clear_latest_negotiation_needed_event();
Eldar Relloead0ec92019-10-21 20:01:311810 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1811 EXPECT_EQ(callee->signaling_state(),
1812 PeerConnectionInterface::kHaveRemoteOffer);
1813 EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal());
1814 // No negotiation needed as track got attached in the answer.
Henrik Boströme574a312020-08-25 08:20:111815 EXPECT_FALSE(callee->observer()->legacy_renegotiation_needed());
1816 EXPECT_FALSE(callee->observer()->has_negotiation_needed_event());
Eldar Relloead0ec92019-10-21 20:01:311817 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 0u);
1818}
1819
1820TEST_F(PeerConnectionJsepTest, RollbackImplicitlyAndNegotiationNeeded) {
1821 RTCConfiguration config;
1822 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
1823 config.enable_implicit_rollback = true;
1824 auto caller = CreatePeerConnection(config);
1825 auto callee = CreatePeerConnection(config);
1826 callee->AddAudioTrack("a");
1827 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
Henrik Boströme574a312020-08-25 08:20:111828 callee->observer()->clear_legacy_renegotiation_needed();
1829 callee->observer()->clear_latest_negotiation_needed_event();
Eldar Relloead0ec92019-10-21 20:01:311830 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1831 EXPECT_EQ(callee->signaling_state(),
1832 PeerConnectionInterface::kHaveRemoteOffer);
Henrik Boströme574a312020-08-25 08:20:111833 EXPECT_FALSE(callee->observer()->legacy_renegotiation_needed());
1834 EXPECT_FALSE(callee->observer()->has_negotiation_needed_event());
Eldar Relloead0ec92019-10-21 20:01:311835 EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal());
Henrik Boströme574a312020-08-25 08:20:111836 EXPECT_TRUE(callee->observer()->legacy_renegotiation_needed());
1837 EXPECT_TRUE(callee->observer()->has_negotiation_needed_event());
Eldar Relloead0ec92019-10-21 20:01:311838 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 0u);
1839}
1840
1841TEST_F(PeerConnectionJsepTest, AttemptToRollbackImplicitly) {
Eldar Rello5ab79e62019-10-09 15:29:441842 RTCConfiguration config;
1843 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
1844 config.enable_implicit_rollback = true;
1845 auto caller = CreatePeerConnection(config);
1846 auto callee = CreatePeerConnection(config);
1847 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
1848 EXPECT_FALSE(callee->SetRemoteDescription(
1849 CreateSessionDescription(SdpType::kOffer, "invalid sdp")));
1850 EXPECT_EQ(callee->signaling_state(),
1851 PeerConnectionInterface::kHaveLocalOffer);
1852}
1853
1854TEST_F(PeerConnectionJsepTest, RollbackRemovesTransceiver) {
1855 auto caller = CreatePeerConnection();
1856 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1857 auto callee = CreatePeerConnection();
1858 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
Eldar Relloead0ec92019-10-21 20:01:311859 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
Eldar Rello5ab79e62019-10-09 15:29:441860 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
Eldar Relloead0ec92019-10-21 20:01:311861 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 0u);
1862 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 1u);
Eldar Rello5ab79e62019-10-09 15:29:441863}
1864
1865TEST_F(PeerConnectionJsepTest, RollbackKeepsTransceiverAndClearsMid) {
1866 auto caller = CreatePeerConnection();
1867 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1868 auto callee = CreatePeerConnection();
1869 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1870 callee->AddAudioTrack("a");
Eldar Relloead0ec92019-10-21 20:01:311871 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
Eldar Rello5ab79e62019-10-09 15:29:441872 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
1873 // Transceiver can't be removed as track was added to it.
Eldar Relloead0ec92019-10-21 20:01:311874 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
Eldar Rello5ab79e62019-10-09 15:29:441875 // Mid got cleared to make it reusable.
1876 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), absl::nullopt);
1877 // Transceiver should be counted as addTrack-created after rollback.
1878 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
Eldar Relloead0ec92019-10-21 20:01:311879 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
1880 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 1u);
Eldar Rello5ab79e62019-10-09 15:29:441881}
1882
Eldar Rello353a7182019-11-25 16:49:441883TEST_F(PeerConnectionJsepTest,
1884 RollbackKeepsTransceiverAfterAddTrackEvenWhenTrackIsNulled) {
1885 auto caller = CreatePeerConnection();
1886 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1887 auto callee = CreatePeerConnection();
1888 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1889 callee->AddAudioTrack("a");
1890 callee->pc()->GetTransceivers()[0]->sender()->SetTrack(nullptr);
1891 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->sender()->track(), nullptr);
1892 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
1893 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
1894 // Transceiver can't be removed as track was added to it.
1895 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
1896 // Mid got cleared to make it reusable.
1897 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), absl::nullopt);
1898 // Transceiver should be counted as addTrack-created after rollback.
1899 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1900 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
1901 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 1u);
1902}
1903
Eldar Rello5ab79e62019-10-09 15:29:441904TEST_F(PeerConnectionJsepTest, RollbackRestoresMid) {
1905 auto caller = CreatePeerConnection();
1906 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1907 auto callee = CreatePeerConnection();
1908 callee->AddAudioTrack("a");
1909 auto offer = callee->CreateOffer();
1910 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
Eldar Relloead0ec92019-10-21 20:01:311911 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
Eldar Rello5ab79e62019-10-09 15:29:441912 EXPECT_NE(callee->pc()->GetTransceivers()[0]->mid(), absl::nullopt);
1913 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
1914 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), absl::nullopt);
1915 EXPECT_TRUE(callee->SetLocalDescription(std::move(offer)));
1916}
1917
1918TEST_F(PeerConnectionJsepTest, RollbackRestoresMidAndRemovesTransceiver) {
1919 auto callee = CreatePeerConnection();
1920 callee->AddVideoTrack("a");
1921 auto offer = callee->CreateOffer();
1922 auto caller = CreatePeerConnection();
1923 caller->AddAudioTrack("b");
1924 caller->AddVideoTrack("c");
1925 auto mid = callee->pc()->GetTransceivers()[0]->mid();
1926 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
Eldar Relloead0ec92019-10-21 20:01:311927 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 2u);
Eldar Rello5ab79e62019-10-09 15:29:441928 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
Eldar Relloead0ec92019-10-21 20:01:311929 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
Eldar Rello5ab79e62019-10-09 15:29:441930 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), mid);
1931 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->media_type(),
1932 cricket::MEDIA_TYPE_VIDEO);
1933 EXPECT_TRUE(callee->SetLocalDescription(std::move(offer)));
Eldar Relloead0ec92019-10-21 20:01:311934 EXPECT_EQ(callee->observer()->remove_track_events_.size(),
1935 callee->observer()->add_track_events_.size());
1936}
1937
1938TEST_F(PeerConnectionJsepTest, RollbackHasNoEffectOnStableTransceivers) {
1939 auto callee = CreatePeerConnection();
1940 callee->AddVideoTrack("a");
1941 auto caller = CreatePeerConnection();
1942 caller->AddAudioTrack("b");
1943 caller->AddVideoTrack("c");
1944 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1945 EXPECT_TRUE(
1946 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1947 // In stable don't add or remove anything.
Henrik Boströme574a312020-08-25 08:20:111948 callee->observer()->clear_legacy_renegotiation_needed();
1949 callee->observer()->clear_latest_negotiation_needed_event();
Eldar Relloead0ec92019-10-21 20:01:311950 size_t transceiver_count = callee->pc()->GetTransceivers().size();
1951 auto mid_0 = callee->pc()->GetTransceivers()[0]->mid();
1952 auto mid_1 = callee->pc()->GetTransceivers()[1]->mid();
1953 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1954 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
1955 EXPECT_EQ(callee->pc()->GetTransceivers().size(), transceiver_count);
1956 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), mid_0);
1957 EXPECT_EQ(callee->pc()->GetTransceivers()[1]->mid(), mid_1);
1958 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 0u);
Henrik Boströme574a312020-08-25 08:20:111959 EXPECT_FALSE(callee->observer()->legacy_renegotiation_needed());
1960 EXPECT_FALSE(callee->observer()->has_negotiation_needed_event());
Eldar Rello5ab79e62019-10-09 15:29:441961}
1962
1963TEST_F(PeerConnectionJsepTest, ImplicitlyRollbackTransceiversWithSameMids) {
1964 RTCConfiguration config;
1965 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
1966 config.enable_implicit_rollback = true;
1967 auto caller = CreatePeerConnection(config);
1968 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
1969 auto callee = CreatePeerConnection(config);
1970 callee->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
1971 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
1972 auto initial_mid = callee->pc()->GetTransceivers()[0]->mid();
1973 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
Eldar Relloead0ec92019-10-21 20:01:311974 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 2u);
Eldar Rello5ab79e62019-10-09 15:29:441975 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), absl::nullopt);
1976 EXPECT_EQ(callee->pc()->GetTransceivers()[1]->mid(),
1977 caller->pc()->GetTransceivers()[0]->mid());
1978 EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal()); // Go to stable.
1979 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
1980 EXPECT_NE(callee->pc()->GetTransceivers()[0]->mid(), initial_mid);
1981}
1982
1983TEST_F(PeerConnectionJsepTest, RollbackToNegotiatedStableState) {
1984 RTCConfiguration config;
1985 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
1986 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
1987 auto caller = CreatePeerConnection(config);
1988 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1989 auto callee = CreatePeerConnection(config);
1990 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1991 EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal());
1992 caller->AddVideoTrack("a");
1993 callee->AddVideoTrack("b");
1994 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
Eldar Relloead0ec92019-10-21 20:01:311995 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 2u);
Eldar Rello5ab79e62019-10-09 15:29:441996 auto audio_transport =
1997 callee->pc()->GetTransceivers()[0]->sender()->dtls_transport();
1998 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
1999 callee->pc()->GetTransceivers()[1]->sender()->dtls_transport());
2000 EXPECT_NE(callee->pc()->GetTransceivers()[1]->sender()->dtls_transport(),
2001 nullptr);
2002 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
2003 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
2004 audio_transport); // Audio must remain working after rollback.
2005 EXPECT_EQ(callee->pc()->GetTransceivers()[1]->sender()->dtls_transport(),
2006 nullptr);
2007 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2008
2009 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
2010 audio_transport); // Audio transport is still the same.
2011}
2012
Eldar Rello353a7182019-11-25 16:49:442013TEST_F(PeerConnectionJsepTest, RollbackHasToDestroyTransport) {
2014 RTCConfiguration config;
2015 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
2016 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
2017 auto pc = CreatePeerConnection(config);
2018 pc->AddAudioTrack("a");
2019 pc->AddVideoTrack("b");
2020 EXPECT_TRUE(pc->CreateOfferAndSetAsLocal());
2021 auto offer = pc->CreateOffer();
2022 EXPECT_EQ(pc->pc()->GetTransceivers().size(), 2u);
2023 auto audio_transport =
2024 pc->pc()->GetTransceivers()[0]->sender()->dtls_transport();
2025 EXPECT_EQ(pc->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
2026 pc->pc()->GetTransceivers()[1]->sender()->dtls_transport());
2027 EXPECT_NE(pc->pc()->GetTransceivers()[1]->sender()->dtls_transport(),
2028 nullptr);
2029 EXPECT_TRUE(pc->SetRemoteDescription(pc->CreateRollback()));
2030 EXPECT_TRUE(pc->SetLocalDescription(std::move(offer)));
2031 EXPECT_NE(pc->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
2032 nullptr);
2033 EXPECT_NE(pc->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
2034 audio_transport);
2035}
2036
Eldar Relloead0ec92019-10-21 20:01:312037TEST_F(PeerConnectionJsepTest, RollbackLocalDirectionChange) {
2038 auto caller = CreatePeerConnection();
2039 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
2040 auto callee = CreatePeerConnection();
2041 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2042 EXPECT_TRUE(
2043 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
2044 callee->AddAudioTrack("a");
Harald Alvestrand6060df52020-08-11 07:54:022045 callee->pc()->GetTransceivers()[0]->SetDirectionWithError(
Eldar Relloead0ec92019-10-21 20:01:312046 RtpTransceiverDirection::kSendOnly);
2047 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2048 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
2049 auto audio_transport =
2050 callee->pc()->GetTransceivers()[0]->receiver()->dtls_transport();
2051 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
2052 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->direction(),
2053 RtpTransceiverDirection::kSendOnly);
2054 // One way audio must remain working after rollback as local direction change
2055 // comes in effect after completing full negotiation round.
2056 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->receiver()->dtls_transport(),
2057 audio_transport);
2058}
2059
2060TEST_F(PeerConnectionJsepTest, RollbackRemoteDirectionChange) {
2061 auto caller = CreatePeerConnection();
2062 auto caller_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
2063 auto callee = CreatePeerConnection();
2064 callee->AddAudioTrack("a");
2065 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2066 EXPECT_TRUE(
2067 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
2068 // In stable make remote audio receive only.
Harald Alvestrand6060df52020-08-11 07:54:022069 caller_transceiver->SetDirectionWithError(RtpTransceiverDirection::kRecvOnly);
Eldar Relloead0ec92019-10-21 20:01:312070 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2071 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
2072 // The direction attribute is not modified by the offer.
2073 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->direction(),
2074 RtpTransceiverDirection::kSendRecv);
2075 auto audio_transport =
2076 callee->pc()->GetTransceivers()[0]->sender()->dtls_transport();
2077 EXPECT_EQ(callee->observer()->add_track_events_.size(), 1u);
2078 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 1u);
2079 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
2080 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
2081 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->direction(),
2082 RtpTransceiverDirection::kSendRecv);
2083 // One way audio must remain working after rollback.
2084 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
2085 audio_transport);
2086 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 1u);
2087}
2088
Eldar Rello5ab79e62019-10-09 15:29:442089TEST_F(PeerConnectionJsepTest, RollbackAfterMultipleSLD) {
2090 auto callee = CreatePeerConnection();
2091 callee->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
2092 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2093 callee->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2094 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
Henrik Boströme574a312020-08-25 08:20:112095 callee->observer()->clear_legacy_renegotiation_needed();
2096 callee->observer()->clear_latest_negotiation_needed_event();
Eldar Rello5ab79e62019-10-09 15:29:442097 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
Henrik Boströme574a312020-08-25 08:20:112098 EXPECT_TRUE(callee->observer()->legacy_renegotiation_needed());
2099 EXPECT_TRUE(callee->observer()->has_negotiation_needed_event());
Eldar Relloead0ec92019-10-21 20:01:312100 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 2u);
Eldar Rello5ab79e62019-10-09 15:29:442101 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), absl::nullopt);
2102 EXPECT_EQ(callee->pc()->GetTransceivers()[1]->mid(), absl::nullopt);
2103}
2104
2105TEST_F(PeerConnectionJsepTest, NoRollbackNeeded) {
2106 auto caller = CreatePeerConnection();
2107 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
2108 auto callee = CreatePeerConnection();
2109 callee->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
2110 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
2111 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
2112 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2113 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2114}
2115
Eldar Rello353a7182019-11-25 16:49:442116TEST_F(PeerConnectionJsepTest, RollbackMultipleStreamChanges) {
2117 auto callee = CreatePeerConnection();
2118 auto caller = CreatePeerConnection();
2119 caller->AddAudioTrack("a_1", {"id_1"});
2120 caller->AddVideoTrack("v_0", {"id_0"}); // Provide an extra stream id.
2121 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2122 EXPECT_TRUE(
2123 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
2124 caller->pc()->GetTransceivers()[0]->sender()->SetStreams({"id_2"});
2125 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2126 caller->pc()->GetTransceivers()[0]->sender()->SetStreams({"id_3"});
2127 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2128 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->receiver()->stream_ids()[0],
2129 "id_3");
2130 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
2131 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->receiver()->stream_ids().size(),
2132 1u);
2133 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->receiver()->stream_ids()[0],
2134 "id_1");
2135}
2136
Eldar Rellod85ea752020-02-19 18:41:072137TEST_F(PeerConnectionJsepTest, DataChannelImplicitRollback) {
2138 RTCConfiguration config;
2139 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
2140 config.enable_implicit_rollback = true;
2141 auto caller = CreatePeerConnection(config);
2142 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2143 auto callee = CreatePeerConnection(config);
2144 callee->CreateDataChannel("dummy");
2145 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2146 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2147 EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal());
Henrik Boströme574a312020-08-25 08:20:112148 EXPECT_TRUE(callee->observer()->legacy_renegotiation_needed());
2149 EXPECT_TRUE(callee->observer()->has_negotiation_needed_event());
Eldar Rellod85ea752020-02-19 18:41:072150 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2151}
2152
2153TEST_F(PeerConnectionJsepTest, RollbackRemoteDataChannelThenAddTransceiver) {
2154 auto caller = CreatePeerConnection();
2155 auto callee = CreatePeerConnection();
2156 caller->CreateDataChannel("dummy");
2157 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2158 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
2159 callee->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2160 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2161}
2162
2163TEST_F(PeerConnectionJsepTest,
2164 RollbackRemoteDataChannelThenAddTransceiverAndDataChannel) {
2165 auto caller = CreatePeerConnection();
2166 auto callee = CreatePeerConnection();
2167 caller->CreateDataChannel("dummy");
2168 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2169 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
2170 callee->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2171 callee->CreateDataChannel("dummy");
2172 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2173}
2174
2175TEST_F(PeerConnectionJsepTest, RollbackRemoteDataChannelThenAddDataChannel) {
2176 auto caller = CreatePeerConnection();
2177 auto callee = CreatePeerConnection();
2178 caller->CreateDataChannel("dummy");
2179 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2180 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
2181 callee->CreateDataChannel("dummy");
2182 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2183}
2184
2185TEST_F(PeerConnectionJsepTest, RollbackRemoteTransceiverThenAddDataChannel) {
2186 auto caller = CreatePeerConnection();
2187 auto callee = CreatePeerConnection();
2188 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2189 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2190 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
2191 callee->CreateDataChannel("dummy");
2192 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2193}
2194
2195TEST_F(PeerConnectionJsepTest,
2196 RollbackRemoteTransceiverThenAddDataChannelAndTransceiver) {
2197 auto caller = CreatePeerConnection();
2198 auto callee = CreatePeerConnection();
2199 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2200 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2201 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
2202 callee->CreateDataChannel("dummy");
2203 callee->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2204 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2205}
2206
Eldar Rellod9ebe012020-03-18 18:41:452207TEST_F(PeerConnectionJsepTest, RollbackRtpDataChannel) {
2208 RTCConfiguration config;
2209 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
2210 config.enable_rtp_data_channel = true;
2211 auto pc = CreatePeerConnection(config);
2212 pc->CreateDataChannel("dummy");
2213 auto offer = pc->CreateOffer();
2214 EXPECT_TRUE(pc->CreateOfferAndSetAsLocal());
2215 EXPECT_TRUE(pc->SetRemoteDescription(pc->CreateRollback()));
2216 EXPECT_TRUE(pc->SetLocalDescription(std::move(offer)));
2217}
2218
Steve Antondcc3c022017-12-23 00:02:542219} // namespace webrtc