1 /*
2 * Copyright 2017 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include <memory>
12
13 #include "api/task_queue/default_task_queue_factory.h"
14 #include "api/transport/field_trial_based_config.h"
15 #include "media/engine/webrtc_media_engine.h"
16 #include "media/engine/webrtc_media_engine_defaults.h"
17 #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"
21 #ifdef WEBRTC_ANDROID
22 #include "pc/test/android_test_initializer.h"
23 #endif
24 #include "pc/test/fake_audio_capture_module.h"
25 #include "rtc_base/gunit.h"
26 #include "rtc_base/virtual_socket_server.h"
27 #include "test/gmock.h"
28 #include "test/pc/sctp/fake_sctp_transport.h"
29
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
36 namespace webrtc {
37
38 using cricket::MediaContentDescription;
39 using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
40 using ::testing::Combine;
41 using ::testing::ElementsAre;
42 using ::testing::UnorderedElementsAre;
43 using ::testing::Values;
44
CreatePeerConnectionFactoryDependencies()45 PeerConnectionFactoryDependencies 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();
51 dependencies.trials = std::make_unique<FieldTrialBasedConfig>();
52 cricket::MediaEngineDependencies media_deps;
53 media_deps.task_queue_factory = dependencies.task_queue_factory.get();
54 media_deps.adm = FakeAudioCaptureModule::Create();
55 media_deps.trials = dependencies.trials.get();
56 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 }
62
63 class PeerConnectionJsepTest : public ::testing::Test {
64 protected:
65 typedef std::unique_ptr<PeerConnectionWrapper> WrapperPtr;
66
PeerConnectionJsepTest()67 PeerConnectionJsepTest()
68 : vss_(new rtc::VirtualSocketServer()), main_(vss_.get()) {
69 #ifdef WEBRTC_ANDROID
70 InitializeAndroidObjects();
71 #endif
72 }
73
CreatePeerConnection()74 WrapperPtr CreatePeerConnection() {
75 RTCConfiguration config;
76 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
77 return CreatePeerConnection(config);
78 }
79
CreatePeerConnection(const RTCConfiguration & config)80 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
81 rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory =
82 CreateModularPeerConnectionFactory(
83 CreatePeerConnectionFactoryDependencies());
84 auto observer = std::make_unique<MockPeerConnectionObserver>();
85 auto pc = pc_factory->CreatePeerConnection(config, nullptr, nullptr,
86 observer.get());
87 if (!pc) {
88 return nullptr;
89 }
90
91 observer->SetPeerConnectionInterface(pc.get());
92 return std::make_unique<PeerConnectionWrapper>(pc_factory, pc,
93 std::move(observer));
94 }
95
96 std::unique_ptr<rtc::VirtualSocketServer> vss_;
97 rtc::AutoSocketServerThread main_;
98 };
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.
TEST_F(PeerConnectionJsepTest,EmptyInitialOffer)104 TEST_F(PeerConnectionJsepTest, EmptyInitialOffer) {
105 auto caller = CreatePeerConnection();
106
107 auto offer = caller->CreateOffer();
108 ASSERT_EQ(0u, offer->description()->contents().size());
109 }
110
111 // Test that an initial offer with one audio track generates one audio media
112 // section.
TEST_F(PeerConnectionJsepTest,AudioOnlyInitialOffer)113 TEST_F(PeerConnectionJsepTest, AudioOnlyInitialOffer) {
114 auto caller = CreatePeerConnection();
115 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
116
117 auto offer = caller->CreateOffer();
118 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
TEST_F(PeerConnectionJsepTest,VideoOnlyInitialOffer)125 TEST_F(PeerConnectionJsepTest, VideoOnlyInitialOffer) {
126 auto caller = CreatePeerConnection();
127 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
128
129 auto offer = caller->CreateOffer();
130 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
135 // Test that an initial offer with one data channel generates one data media
136 // section.
TEST_F(PeerConnectionJsepTest,DataOnlyInitialOffer)137 TEST_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.
TEST_F(PeerConnectionJsepTest,MultipleDataChannelsCreateOnlyOneDataSection)149 TEST_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
159 // 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.
TEST_F(PeerConnectionJsepTest,MediaSectionsInInitialOfferOrderedCorrectly)162 TEST_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);
169
170 auto offer = caller->CreateOffer();
171 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.
TEST_F(PeerConnectionJsepTest,MediaSectionsInInitialOfferHaveDifferentMids)194 TEST_F(PeerConnectionJsepTest, MediaSectionsInInitialOfferHaveDifferentMids) {
195 auto caller = CreatePeerConnection();
196 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
197 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
198
199 auto offer = caller->CreateOffer();
200 auto contents = offer->description()->contents();
201 ASSERT_EQ(2u, contents.size());
202 EXPECT_NE(contents[0].name, contents[1].name);
203 }
204
TEST_F(PeerConnectionJsepTest,StoppedTransceiverHasNoMediaSectionInInitialOffer)205 TEST_F(PeerConnectionJsepTest,
206 StoppedTransceiverHasNoMediaSectionInInitialOffer) {
207 auto caller = CreatePeerConnection();
208 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
209 transceiver->StopInternal();
210
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
TEST_F(PeerConnectionJsepTest,SetLocalEmptyOfferCreatesNoTransceivers)217 TEST_F(PeerConnectionJsepTest, SetLocalEmptyOfferCreatesNoTransceivers) {
218 auto caller = CreatePeerConnection();
219
220 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
TEST_F(PeerConnectionJsepTest,SetLocalOfferSetsTransceiverMid)227 TEST_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.
TEST_F(PeerConnectionJsepTest,SetRemoteOfferCreatesTransceivers)246 TEST_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());
256
257 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, transceivers[0]->media_type());
258 EXPECT_EQ(caller_audio->mid(), transceivers[0]->mid());
259 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly, transceivers[0]->direction());
260 EXPECT_EQ(0u, transceivers[0]->sender()->stream_ids().size());
261
262 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, transceivers[1]->media_type());
263 EXPECT_EQ(caller_video->mid(), transceivers[1]->mid());
264 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly, transceivers[1]->direction());
265 EXPECT_EQ(0u, transceivers[1]->sender()->stream_ids().size());
266 }
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.
TEST_F(PeerConnectionJsepTest,SetRemoteOfferReusesTransceiverFromAddTrack)273 TEST_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.
TEST_F(PeerConnectionJsepTest,SetRemoteOfferDoesNotReuseTransceiverIfDirectionSendOnly)292 TEST_F(PeerConnectionJsepTest,
293 SetRemoteOfferDoesNotReuseTransceiverIfDirectionSendOnly) {
294 auto caller = CreatePeerConnection();
295 caller->AddAudioTrack("a");
296 auto caller_audio = caller->pc()->GetTransceivers()[0];
297 caller_audio->SetDirectionWithError(RtpTransceiverDirection::kSendOnly);
298 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());
305 EXPECT_EQ(absl::nullopt, transceivers[0]->mid());
306 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.
TEST_F(PeerConnectionJsepTest,SetRemoteOfferDoesNotReuseTransceiverFromAddTransceiver)312 TEST_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());
323 EXPECT_EQ(absl::nullopt, transceivers[0]->mid());
324 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.
TEST_F(PeerConnectionJsepTest,SetRemoteOfferDoesNotReuseTransceiverOfWrongType)331 TEST_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());
342 EXPECT_EQ(absl::nullopt, transceivers[0]->mid());
343 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.
TEST_F(PeerConnectionJsepTest,SetRemoteOfferDoesNotReuseStoppedTransceiver)350 TEST_F(PeerConnectionJsepTest, SetRemoteOfferDoesNotReuseStoppedTransceiver) {
351 auto caller = CreatePeerConnection();
352 caller->AddAudioTrack("a");
353 auto callee = CreatePeerConnection();
354 callee->AddAudioTrack("a");
355 callee->pc()->GetTransceivers()[0]->StopInternal();
356
357 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
358
359 auto transceivers = callee->pc()->GetTransceivers();
360 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();
364 ASSERT_EQ(1u, transceivers.size());
365 EXPECT_EQ(caller->pc()->GetTransceivers()[0]->mid(), transceivers[0]->mid());
366 EXPECT_FALSE(transceivers[0]->stopped());
367 }
368
369 // Test that audio and video transceivers created on the remote side with
370 // AddTrack will all be reused if there is the same number of audio/video tracks
371 // in the remote offer. Additionally, this tests that transceivers are
372 // successfully matched even if they are in a different order on the remote
373 // side.
TEST_F(PeerConnectionJsepTest,SetRemoteOfferReusesTransceiversOfBothTypes)374 TEST_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.
TEST_F(PeerConnectionJsepTest,CreateAnswerHasSameMidsAsOffer)395 TEST_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);
400 caller->CreateDataChannel("dc");
401 auto callee = CreatePeerConnection();
402
403 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)));
408
409 auto answer = callee->CreateAnswer();
410 auto contents = answer->description()->contents();
411 ASSERT_EQ(4u, contents.size());
412 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, contents[0].media_description()->type());
413 EXPECT_EQ(first_transceiver->mid(), contents[0].name);
414 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, contents[1].media_description()->type());
415 EXPECT_EQ(second_transceiver->mid(), contents[1].name);
416 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, contents[2].media_description()->type());
417 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);
420 }
421
422 // Test that an answering media section is marked as rejected if the underlying
423 // transceiver has been stopped.
TEST_F(PeerConnectionJsepTest,CreateAnswerRejectsStoppedTransceiver)424 TEST_F(PeerConnectionJsepTest, CreateAnswerRejectsStoppedTransceiver) {
425 auto caller = CreatePeerConnection();
426 caller->AddAudioTrack("a");
427 auto callee = CreatePeerConnection();
428
429 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
430
431 callee->pc()->GetTransceivers()[0]->StopInternal();
432
433 auto answer = callee->CreateAnswer();
434 auto contents = answer->description()->contents();
435 ASSERT_EQ(1u, contents.size());
436 EXPECT_TRUE(contents[0].rejected);
437 }
438
439 // Test that CreateAnswer will generate media sections which will only send or
440 // receive if the offer indicates it can do the reciprocating direction.
441 // The full matrix is tested more extensively in MediaSession.
TEST_F(PeerConnectionJsepTest,CreateAnswerNegotiatesDirection)442 TEST_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.
TEST_F(PeerConnectionJsepTest,SetLocalAnswerUpdatesCurrentDirection)465 TEST_F(PeerConnectionJsepTest, SetLocalAnswerUpdatesCurrentDirection) {
466 auto caller = CreatePeerConnection();
467 auto caller_audio = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
468 caller_audio->SetDirectionWithError(RtpTransceiverDirection::kRecvOnly);
469 auto callee = CreatePeerConnection();
470 callee->AddAudioTrack("a");
471
472 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
473 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
474
475 auto transceivers = callee->pc()->GetTransceivers();
476 ASSERT_EQ(1u, transceivers.size());
477 // Since the offer was recvonly and the transceiver direction is sendrecv,
478 // the negotiated direction will be sendonly.
479 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
480 transceivers[0]->current_direction());
481 }
482
483 // Tests for JSEP SetRemoteDescription with a remote answer.
484 // Note that these test only the additional behaviors not covered by
485 // SetRemoteDescription with a remote offer.
486
TEST_F(PeerConnectionJsepTest,SetRemoteAnswerUpdatesCurrentDirection)487 TEST_F(PeerConnectionJsepTest, SetRemoteAnswerUpdatesCurrentDirection) {
488 auto caller = CreatePeerConnection();
489 caller->AddAudioTrack("a");
490 auto callee = CreatePeerConnection();
491 callee->AddAudioTrack("a");
492 auto callee_audio = callee->pc()->GetTransceivers()[0];
493 callee_audio->SetDirectionWithError(RtpTransceiverDirection::kSendOnly);
494
495 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
496 ASSERT_TRUE(
497 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
498
499 auto transceivers = caller->pc()->GetTransceivers();
500 ASSERT_EQ(1u, transceivers.size());
501 // Since the remote transceiver was set to sendonly, the negotiated direction
502 // in the answer would be sendonly which we apply as recvonly to the local
503 // transceiver.
504 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
505 transceivers[0]->current_direction());
506 }
507
508 // Tests for multiple round trips.
509
510 // Test that setting a transceiver with the inactive direction does not stop it
511 // on either the caller or the callee.
TEST_F(PeerConnectionJsepTest,SettingTransceiverInactiveDoesNotStopIt)512 TEST_F(PeerConnectionJsepTest, SettingTransceiverInactiveDoesNotStopIt) {
513 auto caller = CreatePeerConnection();
514 caller->AddAudioTrack("a");
515 auto callee = CreatePeerConnection();
516 callee->AddAudioTrack("a");
517 callee->pc()->GetTransceivers()[0]->SetDirectionWithError(
518 RtpTransceiverDirection::kInactive);
519
520 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
521 ASSERT_TRUE(
522 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
523
524 EXPECT_FALSE(caller->pc()->GetTransceivers()[0]->stopped());
525 EXPECT_FALSE(callee->pc()->GetTransceivers()[0]->stopped());
526 }
527
528 // Test that if a transceiver had been associated and later stopped, then a
529 // media section is still generated for it and the media section is marked as
530 // rejected.
TEST_F(PeerConnectionJsepTest,ReOfferMediaSectionForAssociatedStoppedTransceiverIsRejected)531 TEST_F(PeerConnectionJsepTest,
532 ReOfferMediaSectionForAssociatedStoppedTransceiverIsRejected) {
533 auto caller = CreatePeerConnection();
534 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
535 auto callee = CreatePeerConnection();
536
537 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
538 ASSERT_TRUE(
539 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
540
541 ASSERT_TRUE(transceiver->mid());
542 transceiver->StopInternal();
543
544 auto reoffer = caller->CreateOffer();
545 auto contents = reoffer->description()->contents();
546 ASSERT_EQ(1u, contents.size());
547 EXPECT_TRUE(contents[0].rejected);
548 }
549
550 // Test that stopping an associated transceiver on the caller side will stop the
551 // corresponding transceiver on the remote side when the remote offer is
552 // applied.
TEST_F(PeerConnectionJsepTest,StoppingTransceiverInOfferStopsTransceiverOnRemoteSide)553 TEST_F(PeerConnectionJsepTest,
554 StoppingTransceiverInOfferStopsTransceiverOnRemoteSide) {
555 auto caller = CreatePeerConnection();
556 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
557 auto callee = CreatePeerConnection();
558
559 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
560 ASSERT_TRUE(
561 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
562
563 transceiver->StopInternal();
564
565 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
566
567 auto transceivers = callee->pc()->GetTransceivers();
568 EXPECT_EQ(1u, transceivers.size());
569 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
570 transceivers = callee->pc()->GetTransceivers();
571 EXPECT_EQ(0u, transceivers.size());
572 }
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.
TEST_F(PeerConnectionJsepTest,CreateOfferDoesNotRecycleMediaSectionIfFirstStopped)576 TEST_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);
587 first_transceiver->StopInternal();
588
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
596 // 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.
TEST_F(PeerConnectionJsepTest,RecycleMediaSectionWhenStoppingTransceiverOnAnswerer)599 TEST_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()));
606 std::string first_mid = *first_transceiver->mid();
607 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
608 callee->pc()->GetTransceivers()[0]->StopInternal();
609 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
610 ASSERT_TRUE(
611 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
612 EXPECT_TRUE(first_transceiver->stopped());
613 // First transceivers are dissociated on caller side.
614 ASSERT_EQ(absl::nullopt, first_transceiver->mid());
615 // They are disassociated on callee side.
616 ASSERT_EQ(0u, callee->pc()->GetTransceivers().size());
617
618 // New offer exchange with new transceivers that recycles the m section
619 // correctly.
620 caller->AddAudioTrack("audio2");
621 callee->AddAudioTrack("audio2");
622 auto offer = caller->CreateOffer();
623 auto offer_contents = offer->description()->contents();
624 std::string second_mid = offer_contents[0].name;
625 ASSERT_EQ(1u, offer_contents.size());
626 EXPECT_FALSE(offer_contents[0].rejected);
627 EXPECT_NE(first_mid, second_mid);
628
629 // Setting the offer on each side will dissociate the first transceivers and
630 // associate the new transceivers.
631 ASSERT_TRUE(
632 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
633 EXPECT_EQ(absl::nullopt, first_transceiver->mid());
634 ASSERT_EQ(1u, caller->pc()->GetTransceivers().size());
635 EXPECT_EQ(second_mid, caller->pc()->GetTransceivers()[0]->mid());
636 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
637 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
638 EXPECT_EQ(second_mid, callee->pc()->GetTransceivers()[0]->mid());
639
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();
652 ASSERT_EQ(1u, caller_transceivers.size());
653 EXPECT_EQ(second_mid, caller_transceivers[0]->mid());
654 auto callee_transceivers = callee->pc()->GetTransceivers();
655 ASSERT_EQ(1u, callee_transceivers.size());
656 EXPECT_EQ(second_mid, callee_transceivers[0]->mid());
657 }
658
659 // Test that creating/setting a local offer that recycles an m= section is
660 // idempotent.
TEST_F(PeerConnectionJsepTest,CreateOfferRecyclesWhenOfferingTwice)661 TEST_F(PeerConnectionJsepTest, CreateOfferRecyclesWhenOfferingTwice) {
662 // Do a negotiation with a port 0 for the media section.
663 auto caller = CreatePeerConnection();
664 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
665 auto callee = CreatePeerConnection();
666 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
667 first_transceiver->StopInternal();
668 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
669 caller->AddAudioTrack("audio2");
670
671 // Create a new offer that recycles the media section and set it as a local
672 // description.
673 auto offer = caller->CreateOffer();
674 auto offer_contents = offer->description()->contents();
675 ASSERT_EQ(1u, offer_contents.size());
676 EXPECT_FALSE(offer_contents[0].rejected);
677 ASSERT_TRUE(caller->SetLocalDescription(std::move(offer)));
678 ASSERT_EQ(1u, caller->pc()->GetTransceivers().size());
679 EXPECT_FALSE(caller->pc()->GetTransceivers()[0]->stopped());
680 std::string second_mid = offer_contents[0].name;
681
682 // Create another new offer and set the local description again without the
683 // rest of any negotation ocurring.
684 auto second_offer = caller->CreateOffer();
685 auto second_offer_contents = second_offer->description()->contents();
686 ASSERT_EQ(1u, second_offer_contents.size());
687 EXPECT_FALSE(second_offer_contents[0].rejected);
688 // The mid shouldn't change.
689 EXPECT_EQ(second_mid, second_offer_contents[0].name);
690
691 ASSERT_TRUE(caller->SetLocalDescription(std::move(second_offer)));
692 // Make sure that the caller's transceivers are associated correctly.
693 auto caller_transceivers = caller->pc()->GetTransceivers();
694 ASSERT_EQ(1u, caller_transceivers.size());
695 EXPECT_EQ(second_mid, caller_transceivers[0]->mid());
696 EXPECT_FALSE(caller_transceivers[0]->stopped());
697 }
698
699 // 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.
702 // 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.
708 class RecycleMediaSectionTest
709 : public PeerConnectionJsepTest,
710 public ::testing::WithParamInterface<
711 std::tuple<cricket::MediaType, cricket::MediaType>> {
712 protected:
RecycleMediaSectionTest()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
722 // 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.
TEST_P(RecycleMediaSectionTest,CurrentLocalAndCurrentRemoteRejected)724 TEST_P(RecycleMediaSectionTest, CurrentLocalAndCurrentRemoteRejected) {
725 auto caller = CreatePeerConnection();
726 auto first_transceiver = caller->AddTransceiver(first_type_);
727 auto callee = CreatePeerConnection();
728
729 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
730
731 std::string first_mid = *first_transceiver->mid();
732 first_transceiver->StopInternal();
733
734 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
735
736 auto second_transceiver = caller->AddTransceiver(second_type_);
737
738 // The offer should reuse the previous media section but allocate a new MID
739 // and change the media type.
740 auto offer = caller->CreateOffer();
741 auto offer_contents = offer->description()->contents();
742 ASSERT_EQ(1u, offer_contents.size());
743 EXPECT_FALSE(offer_contents[0].rejected);
744 EXPECT_EQ(second_type_, offer_contents[0].media_description()->type());
745 std::string second_mid = offer_contents[0].name;
746 EXPECT_NE(first_mid, second_mid);
747
748 // Setting the local offer will dissociate the previous transceiver and set
749 // the MID for the new transceiver.
750 ASSERT_TRUE(
751 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
752 EXPECT_EQ(absl::nullopt, first_transceiver->mid());
753 EXPECT_EQ(second_mid, second_transceiver->mid());
754
755 // Setting the remote offer will dissociate the previous transceiver and
756 // create a new transceiver for the media section.
757 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
758 auto callee_transceivers = callee->pc()->GetTransceivers();
759 ASSERT_EQ(1u, callee_transceivers.size());
760 EXPECT_EQ(second_mid, callee_transceivers[0]->mid());
761 EXPECT_EQ(second_type_, callee_transceivers[0]->media_type());
762
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
775 // Setting the remote answer should succeed and not create any new
776 // transceivers.
777 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
778 ASSERT_EQ(1u, caller->pc()->GetTransceivers().size());
779 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
780 }
781
782 // Test that recycling works properly when a new transceiver recycles an m=
783 // section that was rejected in only the current remote description.
TEST_P(RecycleMediaSectionTest,CurrentRemoteOnlyRejected)784 TEST_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];
794 callee_first_transceiver->StopInternal();
795
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();
822 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());
825
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)));
841 ASSERT_EQ(1u, caller->pc()->GetTransceivers().size());
842 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
843 }
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.
TEST_P(RecycleMediaSectionTest,CurrentLocalOnlyRejected)847 TEST_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];
857 callee_first_transceiver->StopInternal();
858
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();
885 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());
888
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)));
904 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
905 ASSERT_EQ(1u, caller->pc()->GetTransceivers().size());
906 }
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.
TEST_P(RecycleMediaSectionTest,PendingLocalRejectedAndNoRemote)911 TEST_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();
918 caller_first_transceiver->StopInternal();
919
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.
TEST_P(RecycleMediaSectionTest,PendingLocalRejectedAndNotRejectedRemote)948 TEST_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();
956 caller_first_transceiver->StopInternal();
957
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.
TEST_P(RecycleMediaSectionTest,PendingRemoteRejectedAndNoLocal)986 TEST_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();
996 caller_first_transceiver->StopInternal();
997
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.
TEST_P(RecycleMediaSectionTest,PendingRemoteRejectedAndNotRejectedLocal)1023 TEST_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();
1033 caller_first_transceiver->StopInternal();
1034
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
1057 // 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.
1061 INSTANTIATE_TEST_SUITE_P(
1062 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
1067 // 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.
TEST_F(PeerConnectionJsepTest,DataChannelDoesNotRecycleMediaSection)1070 TEST_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
1077 transceiver->StopInternal();
1078
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.
TEST_F(PeerConnectionJsepTest,AudioTrackAddedAfterDataSectionInReoffer)1107 TEST_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
1123 // Tests for MID properties.
1124
RenameSection(size_t mline_index,const std::string & new_mid,SessionDescriptionInterface * sdesc)1125 static 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.
TEST_F(PeerConnectionJsepTest,OfferAnswerWithChangedMids)1146 TEST_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.
TEST_F(PeerConnectionJsepTest,CreateOfferGeneratesUniqueMidIfAlreadyTaken)1184 TEST_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
1216 // 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.
TEST_F(PeerConnectionJsepTest,CreateOfferGeneratesUniqueMidForDataSectionIfAlreadyTaken)1218 TEST_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
1250 // Test that a reoffer initiated by the callee adds a new track to the caller.
TEST_F(PeerConnectionJsepTest,CalleeDoesReoffer)1251 TEST_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
1269 // Tests for MSID properties.
1270
1271 // Test that adding a track with AddTrack results in an offer that signals the
1272 // track's ID.
TEST_F(PeerConnectionJsepTest,AddingTrackWithAddTrackSpecifiesTrackId)1273 TEST_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.
TEST_F(PeerConnectionJsepTest,AddingTrackWithAddTransceiverSpecifiesRandomTrackId)1289 TEST_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
1305 // Test that if the transceiver is recvonly or inactive, then no MSID
1306 // information is included in the offer.
TEST_F(PeerConnectionJsepTest,NoMsidInOfferIfTransceiverDirectionHasNoSend)1307 TEST_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.
TEST_F(PeerConnectionJsepTest,NoMsidInAnswerIfNoRespondingTracks)1328 TEST_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.
TEST_F(PeerConnectionJsepTest,IncludeMsidEvenIfDirectionHasChanged)1356 TEST_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
1364 caller->pc()->GetTransceivers()[0]->SetDirectionWithError(
1365 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.
TEST_F(PeerConnectionJsepTest,RemoveMsidIfTransceiverStopped)1385 TEST_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
1392 transceiver->StopInternal();
1393
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
1403 // Test that the callee RtpReceiver created by a call to SetRemoteDescription
1404 // has its ID set to the signaled track ID.
TEST_F(PeerConnectionJsepTest,RtpReceiverCreatedBySetRemoteDescriptionHasSignaledTrackId)1405 TEST_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.
TEST_F(PeerConnectionJsepTest,RtpReceiverCreatedBeforeSetRemoteDescriptionKeepsId)1422 TEST_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
1440 // Test that setting a remote offer with one track that has no streams fires off
1441 // the correct OnAddTrack event.
TEST_F(PeerConnectionJsepTest,SetRemoteOfferWithOneTrackNoStreamFiresOnAddTrack)1442 TEST_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
1452 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());
1457 }
1458
1459 // Test that setting a remote offer with one track that has one stream fires off
1460 // the correct OnAddTrack event.
TEST_F(PeerConnectionJsepTest,SetRemoteOfferWithOneTrackOneStreamFiresOnAddTrack)1461 TEST_F(PeerConnectionJsepTest,
1462 SetRemoteOfferWithOneTrackOneStreamFiresOnAddTrack) {
1463 const std::string kTrackLabel = "audio_track";
1464 const std::string kStreamId = "audio_stream";
1465
1466 auto caller = CreatePeerConnection();
1467 auto callee = CreatePeerConnection();
1468 ASSERT_TRUE(caller->AddAudioTrack(kTrackLabel, {kStreamId}));
1469
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];
1477 EXPECT_EQ(kStreamId, stream->id());
1478 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.
TEST_F(PeerConnectionJsepTest,SetRemoteOfferWithTwoTracksSameStreamFiresOnAddTrack)1488 TEST_F(PeerConnectionJsepTest,
1489 SetRemoteOfferWithTwoTracksSameStreamFiresOnAddTrack) {
1490 const std::string kTrack1Label = "audio_track1";
1491 const std::string kTrack2Label = "audio_track2";
1492 const std::string kSharedStreamId = "stream";
1493
1494 auto caller = CreatePeerConnection();
1495 auto callee = CreatePeerConnection();
1496 ASSERT_TRUE(caller->AddAudioTrack(kTrack1Label, {kSharedStreamId}));
1497 ASSERT_TRUE(caller->AddAudioTrack(kTrack2Label, {kSharedStreamId}));
1498
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
1516 // Test that setting a remote offer with one track that has two streams fires
1517 // off the correct OnAddTrack event.
TEST_F(PeerConnectionJsepTest,SetRemoteOfferWithOneTrackTwoStreamFiresOnAddTrack)1518 TEST_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 }
1537
1538 // Test that if an RtpTransceiver with a current_direction set is stopped, then
1539 // current_direction is changed to null.
TEST_F(PeerConnectionJsepTest,CurrentDirectionResetWhenRtpTransceiverStopped)1540 TEST_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());
1549 transceiver->StopInternal();
1550 EXPECT_EQ(transceiver->current_direction(),
1551 RtpTransceiverDirection::kStopped);
1552 }
1553
1554 // Test that you can't set an answer on a PeerConnection before setting the
1555 // offer.
TEST_F(PeerConnectionJsepTest,AnswerBeforeOfferFails)1556 TEST_F(PeerConnectionJsepTest, AnswerBeforeOfferFails) {
1557 auto caller = CreatePeerConnection();
1558 auto callee = CreatePeerConnection();
1559 caller->AddAudioTrack("audio");
1560
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.
TEST_F(PeerConnectionJsepTest,TwoVideoPlanBToUnifiedPlanFails)1570 TEST_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.
TEST_F(PeerConnectionJsepTest,OneVideoUnifiedPlanToTwoVideoPlanBFails)1585 TEST_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());
1599 }
1600
1601 // Removes the RTP header extension associated with the given URI from the media
1602 // description.
RemoveRtpHeaderExtensionByUri(MediaContentDescription * media_description,absl::string_view uri)1603 static 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.
ClearMids(SessionDescriptionInterface * sdesc)1616 static 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.
TEST_F(PeerConnectionJsepTest,LegacyNoMidAudioOnlyOffer)1636 TEST_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 }
TEST_F(PeerConnectionJsepTest,LegacyNoMidAudioVideoOffer)1648 TEST_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 }
TEST_F(PeerConnectionJsepTest,LegacyNoMidAudioOnlyAnswer)1662 TEST_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 }
TEST_F(PeerConnectionJsepTest,LegacyNoMidAudioVideoAnswer)1675 TEST_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
1691 // 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.
TEST_F(PeerConnectionJsepTest,LegacyNoMidTwoRemoteOffers)1694 TEST_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
1709 // Test that SetLocalDescription fails if a=mid lines are missing.
TEST_F(PeerConnectionJsepTest,SetLocalDescriptionFailsMissingMid)1710 TEST_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
TEST_F(PeerConnectionJsepTest,RollbackSupportedInUnifiedPlan)1725 TEST_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
TEST_F(PeerConnectionJsepTest,RollbackNotSupportedInPlanB)1739 TEST_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
TEST_F(PeerConnectionJsepTest,RollbackFailsInStableState)1751 TEST_F(PeerConnectionJsepTest, RollbackFailsInStableState) {
1752 auto caller = CreatePeerConnection();
1753 EXPECT_FALSE(caller->SetLocalDescription(caller->CreateRollback()));
1754 EXPECT_FALSE(caller->SetRemoteDescription(caller->CreateRollback()));
1755 }
1756
TEST_F(PeerConnectionJsepTest,RollbackToStableStateAndClearLocalOffer)1757 TEST_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
TEST_F(PeerConnectionJsepTest,RollbackToStableStateAndClearRemoteOffer)1770 TEST_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
TEST_F(PeerConnectionJsepTest,RollbackImplicitly)1784 TEST_F(PeerConnectionJsepTest, RollbackImplicitly) {
1785 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);
1794 EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal());
1795 EXPECT_FALSE(callee->observer()->legacy_renegotiation_needed());
1796 EXPECT_FALSE(callee->observer()->has_negotiation_needed_event());
1797 }
1798
TEST_F(PeerConnectionJsepTest,RollbackImplicitlyNegotatiationNotNeeded)1799 TEST_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());
1808 callee->observer()->clear_legacy_renegotiation_needed();
1809 callee->observer()->clear_latest_negotiation_needed_event();
1810 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.
1815 EXPECT_FALSE(callee->observer()->legacy_renegotiation_needed());
1816 EXPECT_FALSE(callee->observer()->has_negotiation_needed_event());
1817 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 0u);
1818 }
1819
TEST_F(PeerConnectionJsepTest,RollbackImplicitlyAndNegotiationNeeded)1820 TEST_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());
1828 callee->observer()->clear_legacy_renegotiation_needed();
1829 callee->observer()->clear_latest_negotiation_needed_event();
1830 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1831 EXPECT_EQ(callee->signaling_state(),
1832 PeerConnectionInterface::kHaveRemoteOffer);
1833 EXPECT_FALSE(callee->observer()->legacy_renegotiation_needed());
1834 EXPECT_FALSE(callee->observer()->has_negotiation_needed_event());
1835 EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal());
1836 EXPECT_TRUE(callee->observer()->legacy_renegotiation_needed());
1837 EXPECT_TRUE(callee->observer()->has_negotiation_needed_event());
1838 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 0u);
1839 }
1840
TEST_F(PeerConnectionJsepTest,AttemptToRollbackImplicitly)1841 TEST_F(PeerConnectionJsepTest, AttemptToRollbackImplicitly) {
1842 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
TEST_F(PeerConnectionJsepTest,RollbackRemovesTransceiver)1854 TEST_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()));
1859 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
1860 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
1861 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 0u);
1862 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 1u);
1863 }
1864
TEST_F(PeerConnectionJsepTest,RollbackKeepsTransceiverAndClearsMid)1865 TEST_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");
1871 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
1872 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
1873 // Transceiver can't be removed as track was added to it.
1874 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
1875 // 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()));
1879 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
1880 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 1u);
1881 }
1882
TEST_F(PeerConnectionJsepTest,RollbackKeepsTransceiverAfterAddTrackEvenWhenTrackIsNulled)1883 TEST_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
TEST_F(PeerConnectionJsepTest,RollbackRestoresMid)1904 TEST_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()));
1911 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
1912 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
TEST_F(PeerConnectionJsepTest,RollbackRestoresInitSendEncodings)1918 TEST_F(PeerConnectionJsepTest, RollbackRestoresInitSendEncodings) {
1919 auto caller = CreatePeerConnection();
1920 RtpTransceiverInit init;
1921 init.direction = RtpTransceiverDirection::kSendRecv;
1922 RtpEncodingParameters encoding;
1923 encoding.rid = "hi";
1924 init.send_encodings.push_back(encoding);
1925 encoding.rid = "mid";
1926 init.send_encodings.push_back(encoding);
1927 encoding.rid = "lo";
1928 init.send_encodings.push_back(encoding);
1929 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init);
1930 auto encodings =
1931 caller->pc()->GetTransceivers()[0]->sender()->init_send_encodings();
1932 EXPECT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
1933 EXPECT_NE(caller->pc()->GetTransceivers()[0]->sender()->init_send_encodings(),
1934 encodings);
1935 EXPECT_TRUE(caller->SetLocalDescription(caller->CreateRollback()));
1936 EXPECT_EQ(caller->pc()->GetTransceivers()[0]->sender()->init_send_encodings(),
1937 encodings);
1938 }
1939
TEST_F(PeerConnectionJsepTest,RollbackDoesNotAffectSendEncodings)1940 TEST_F(PeerConnectionJsepTest, RollbackDoesNotAffectSendEncodings) {
1941 auto caller = CreatePeerConnection();
1942 auto callee = CreatePeerConnection();
1943 RtpTransceiverInit init;
1944 init.direction = RtpTransceiverDirection::kSendOnly;
1945 RtpEncodingParameters encoding;
1946 encoding.rid = "hi";
1947 init.send_encodings.push_back(encoding);
1948 encoding.rid = "mid";
1949 init.send_encodings.push_back(encoding);
1950 encoding.rid = "lo";
1951 init.send_encodings.push_back(encoding);
1952 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init);
1953 callee->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
1954 callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal());
1955 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal());
1956 auto params = caller->pc()->GetTransceivers()[0]->sender()->GetParameters();
1957 EXPECT_TRUE(params.encodings[0].active);
1958 params.encodings[0].active = false;
1959 caller->pc()->GetTransceivers()[0]->sender()->SetParameters(params);
1960 auto offer = caller->CreateOffer();
1961 std::string offer_string;
1962 EXPECT_TRUE(offer.get()->ToString(&offer_string));
1963 std::string simulcast_line =
1964 offer_string.substr(offer_string.find("a=simulcast"));
1965 EXPECT_FALSE(simulcast_line.empty());
1966 EXPECT_TRUE(caller->SetLocalDescription(std::move(offer)));
1967 EXPECT_TRUE(caller->SetLocalDescription(caller->CreateRollback()));
1968 EXPECT_FALSE(caller->pc()
1969 ->GetTransceivers()[0]
1970 ->sender()
1971 ->GetParameters()
1972 .encodings[0]
1973 .active);
1974 offer = caller->CreateOffer();
1975 EXPECT_TRUE(offer.get()->ToString(&offer_string));
1976 EXPECT_EQ(offer_string.substr(offer_string.find("a=simulcast")),
1977 simulcast_line);
1978 }
1979
TEST_F(PeerConnectionJsepTest,RollbackRestoresMidAndRemovesTransceiver)1980 TEST_F(PeerConnectionJsepTest, RollbackRestoresMidAndRemovesTransceiver) {
1981 auto callee = CreatePeerConnection();
1982 callee->AddVideoTrack("a");
1983 auto offer = callee->CreateOffer();
1984 auto caller = CreatePeerConnection();
1985 caller->AddAudioTrack("b");
1986 caller->AddVideoTrack("c");
1987 auto mid = callee->pc()->GetTransceivers()[0]->mid();
1988 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1989 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 2u);
1990 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
1991 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
1992 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), mid);
1993 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->media_type(),
1994 cricket::MEDIA_TYPE_VIDEO);
1995 EXPECT_TRUE(callee->SetLocalDescription(std::move(offer)));
1996 EXPECT_EQ(callee->observer()->remove_track_events_.size(),
1997 callee->observer()->add_track_events_.size());
1998 }
1999
TEST_F(PeerConnectionJsepTest,RollbackHasNoEffectOnStableTransceivers)2000 TEST_F(PeerConnectionJsepTest, RollbackHasNoEffectOnStableTransceivers) {
2001 auto callee = CreatePeerConnection();
2002 callee->AddVideoTrack("a");
2003 auto caller = CreatePeerConnection();
2004 caller->AddAudioTrack("b");
2005 caller->AddVideoTrack("c");
2006 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2007 EXPECT_TRUE(
2008 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
2009 // In stable don't add or remove anything.
2010 callee->observer()->clear_legacy_renegotiation_needed();
2011 callee->observer()->clear_latest_negotiation_needed_event();
2012 size_t transceiver_count = callee->pc()->GetTransceivers().size();
2013 auto mid_0 = callee->pc()->GetTransceivers()[0]->mid();
2014 auto mid_1 = callee->pc()->GetTransceivers()[1]->mid();
2015 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2016 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
2017 EXPECT_EQ(callee->pc()->GetTransceivers().size(), transceiver_count);
2018 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), mid_0);
2019 EXPECT_EQ(callee->pc()->GetTransceivers()[1]->mid(), mid_1);
2020 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 0u);
2021 EXPECT_FALSE(callee->observer()->legacy_renegotiation_needed());
2022 EXPECT_FALSE(callee->observer()->has_negotiation_needed_event());
2023 }
2024
TEST_F(PeerConnectionJsepTest,ImplicitlyRollbackTransceiversWithSameMids)2025 TEST_F(PeerConnectionJsepTest, ImplicitlyRollbackTransceiversWithSameMids) {
2026 RTCConfiguration config;
2027 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
2028 config.enable_implicit_rollback = true;
2029 auto caller = CreatePeerConnection(config);
2030 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2031 auto callee = CreatePeerConnection(config);
2032 callee->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2033 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2034 auto initial_mid = callee->pc()->GetTransceivers()[0]->mid();
2035 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2036 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 2u);
2037 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), absl::nullopt);
2038 EXPECT_EQ(callee->pc()->GetTransceivers()[1]->mid(),
2039 caller->pc()->GetTransceivers()[0]->mid());
2040 EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal()); // Go to stable.
2041 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2042 EXPECT_NE(callee->pc()->GetTransceivers()[0]->mid(), initial_mid);
2043 }
2044
TEST_F(PeerConnectionJsepTest,RollbackToNegotiatedStableState)2045 TEST_F(PeerConnectionJsepTest, RollbackToNegotiatedStableState) {
2046 RTCConfiguration config;
2047 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
2048 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
2049 auto caller = CreatePeerConnection(config);
2050 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
2051 auto callee = CreatePeerConnection(config);
2052 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2053 EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal());
2054 caller->AddVideoTrack("a");
2055 callee->AddVideoTrack("b");
2056 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2057 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 2u);
2058 auto audio_transport =
2059 callee->pc()->GetTransceivers()[0]->sender()->dtls_transport();
2060 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
2061 callee->pc()->GetTransceivers()[1]->sender()->dtls_transport());
2062 EXPECT_NE(callee->pc()->GetTransceivers()[1]->sender()->dtls_transport(),
2063 nullptr);
2064 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
2065 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
2066 audio_transport); // Audio must remain working after rollback.
2067 EXPECT_EQ(callee->pc()->GetTransceivers()[1]->sender()->dtls_transport(),
2068 nullptr);
2069 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2070
2071 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
2072 audio_transport); // Audio transport is still the same.
2073 }
2074
TEST_F(PeerConnectionJsepTest,RollbackHasToDestroyTransport)2075 TEST_F(PeerConnectionJsepTest, RollbackHasToDestroyTransport) {
2076 RTCConfiguration config;
2077 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
2078 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
2079 auto pc = CreatePeerConnection(config);
2080 pc->AddAudioTrack("a");
2081 pc->AddVideoTrack("b");
2082 EXPECT_TRUE(pc->CreateOfferAndSetAsLocal());
2083 auto offer = pc->CreateOffer();
2084 EXPECT_EQ(pc->pc()->GetTransceivers().size(), 2u);
2085 auto audio_transport =
2086 pc->pc()->GetTransceivers()[0]->sender()->dtls_transport();
2087 EXPECT_EQ(pc->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
2088 pc->pc()->GetTransceivers()[1]->sender()->dtls_transport());
2089 EXPECT_NE(pc->pc()->GetTransceivers()[1]->sender()->dtls_transport(),
2090 nullptr);
2091 EXPECT_TRUE(pc->SetRemoteDescription(pc->CreateRollback()));
2092 EXPECT_TRUE(pc->SetLocalDescription(std::move(offer)));
2093 EXPECT_NE(pc->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
2094 nullptr);
2095 EXPECT_NE(pc->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
2096 audio_transport);
2097 }
2098
TEST_F(PeerConnectionJsepTest,RollbackLocalDirectionChange)2099 TEST_F(PeerConnectionJsepTest, RollbackLocalDirectionChange) {
2100 auto caller = CreatePeerConnection();
2101 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
2102 auto callee = CreatePeerConnection();
2103 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2104 EXPECT_TRUE(
2105 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
2106 callee->AddAudioTrack("a");
2107 callee->pc()->GetTransceivers()[0]->SetDirectionWithError(
2108 RtpTransceiverDirection::kSendOnly);
2109 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2110 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
2111 auto audio_transport =
2112 callee->pc()->GetTransceivers()[0]->receiver()->dtls_transport();
2113 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
2114 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->direction(),
2115 RtpTransceiverDirection::kSendOnly);
2116 // One way audio must remain working after rollback as local direction change
2117 // comes in effect after completing full negotiation round.
2118 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->receiver()->dtls_transport(),
2119 audio_transport);
2120 }
2121
TEST_F(PeerConnectionJsepTest,RollbackRemoteDirectionChange)2122 TEST_F(PeerConnectionJsepTest, RollbackRemoteDirectionChange) {
2123 auto caller = CreatePeerConnection();
2124 auto caller_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
2125 auto callee = CreatePeerConnection();
2126 callee->AddAudioTrack("a");
2127 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2128 EXPECT_TRUE(
2129 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
2130 // In stable make remote audio receive only.
2131 caller_transceiver->SetDirectionWithError(RtpTransceiverDirection::kRecvOnly);
2132 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2133 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
2134 // The direction attribute is not modified by the offer.
2135 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->direction(),
2136 RtpTransceiverDirection::kSendRecv);
2137 auto audio_transport =
2138 callee->pc()->GetTransceivers()[0]->sender()->dtls_transport();
2139 EXPECT_EQ(callee->observer()->add_track_events_.size(), 1u);
2140 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 1u);
2141 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
2142 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
2143 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->direction(),
2144 RtpTransceiverDirection::kSendRecv);
2145 // One way audio must remain working after rollback.
2146 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
2147 audio_transport);
2148 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 1u);
2149 }
2150
TEST_F(PeerConnectionJsepTest,RollbackAfterMultipleSLD)2151 TEST_F(PeerConnectionJsepTest, RollbackAfterMultipleSLD) {
2152 auto callee = CreatePeerConnection();
2153 callee->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
2154 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2155 callee->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2156 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2157 callee->observer()->clear_legacy_renegotiation_needed();
2158 callee->observer()->clear_latest_negotiation_needed_event();
2159 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
2160 EXPECT_TRUE(callee->observer()->legacy_renegotiation_needed());
2161 EXPECT_TRUE(callee->observer()->has_negotiation_needed_event());
2162 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 2u);
2163 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), absl::nullopt);
2164 EXPECT_EQ(callee->pc()->GetTransceivers()[1]->mid(), absl::nullopt);
2165 }
2166
TEST_F(PeerConnectionJsepTest,NoRollbackNeeded)2167 TEST_F(PeerConnectionJsepTest, NoRollbackNeeded) {
2168 auto caller = CreatePeerConnection();
2169 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
2170 auto callee = CreatePeerConnection();
2171 callee->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
2172 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
2173 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
2174 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2175 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2176 }
2177
TEST_F(PeerConnectionJsepTest,RollbackMultipleStreamChanges)2178 TEST_F(PeerConnectionJsepTest, RollbackMultipleStreamChanges) {
2179 auto callee = CreatePeerConnection();
2180 auto caller = CreatePeerConnection();
2181 caller->AddAudioTrack("a_1", {"id_1"});
2182 caller->AddVideoTrack("v_0", {"id_0"}); // Provide an extra stream id.
2183 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2184 EXPECT_TRUE(
2185 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
2186 caller->pc()->GetTransceivers()[0]->sender()->SetStreams({"id_2"});
2187 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2188 caller->pc()->GetTransceivers()[0]->sender()->SetStreams({"id_3"});
2189 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2190 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->receiver()->stream_ids()[0],
2191 "id_3");
2192 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
2193 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->receiver()->stream_ids().size(),
2194 1u);
2195 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->receiver()->stream_ids()[0],
2196 "id_1");
2197 }
2198
TEST_F(PeerConnectionJsepTest,DataChannelImplicitRollback)2199 TEST_F(PeerConnectionJsepTest, DataChannelImplicitRollback) {
2200 RTCConfiguration config;
2201 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
2202 config.enable_implicit_rollback = true;
2203 auto caller = CreatePeerConnection(config);
2204 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2205 auto callee = CreatePeerConnection(config);
2206 callee->CreateDataChannel("dummy");
2207 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2208 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2209 EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal());
2210 EXPECT_TRUE(callee->observer()->legacy_renegotiation_needed());
2211 EXPECT_TRUE(callee->observer()->has_negotiation_needed_event());
2212 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2213 }
2214
TEST_F(PeerConnectionJsepTest,RollbackRemoteDataChannelThenAddTransceiver)2215 TEST_F(PeerConnectionJsepTest, RollbackRemoteDataChannelThenAddTransceiver) {
2216 auto caller = CreatePeerConnection();
2217 auto callee = CreatePeerConnection();
2218 caller->CreateDataChannel("dummy");
2219 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2220 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
2221 callee->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2222 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2223 }
2224
TEST_F(PeerConnectionJsepTest,RollbackRemoteDataChannelThenAddTransceiverAndDataChannel)2225 TEST_F(PeerConnectionJsepTest,
2226 RollbackRemoteDataChannelThenAddTransceiverAndDataChannel) {
2227 auto caller = CreatePeerConnection();
2228 auto callee = CreatePeerConnection();
2229 caller->CreateDataChannel("dummy");
2230 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2231 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
2232 callee->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2233 callee->CreateDataChannel("dummy");
2234 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2235 }
2236
TEST_F(PeerConnectionJsepTest,RollbackRemoteDataChannelThenAddDataChannel)2237 TEST_F(PeerConnectionJsepTest, RollbackRemoteDataChannelThenAddDataChannel) {
2238 auto caller = CreatePeerConnection();
2239 auto callee = CreatePeerConnection();
2240 caller->CreateDataChannel("dummy");
2241 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2242 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
2243 callee->CreateDataChannel("dummy");
2244 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2245 }
2246
TEST_F(PeerConnectionJsepTest,RollbackRemoteTransceiverThenAddDataChannel)2247 TEST_F(PeerConnectionJsepTest, RollbackRemoteTransceiverThenAddDataChannel) {
2248 auto caller = CreatePeerConnection();
2249 auto callee = CreatePeerConnection();
2250 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2251 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2252 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
2253 callee->CreateDataChannel("dummy");
2254 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2255 }
2256
TEST_F(PeerConnectionJsepTest,RollbackRemoteTransceiverThenAddDataChannelAndTransceiver)2257 TEST_F(PeerConnectionJsepTest,
2258 RollbackRemoteTransceiverThenAddDataChannelAndTransceiver) {
2259 auto caller = CreatePeerConnection();
2260 auto callee = CreatePeerConnection();
2261 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2262 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2263 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
2264 callee->CreateDataChannel("dummy");
2265 callee->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2266 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2267 }
2268
TEST_F(PeerConnectionJsepTest,RollbackRtpDataChannel)2269 TEST_F(PeerConnectionJsepTest, RollbackRtpDataChannel) {
2270 RTCConfiguration config;
2271 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
2272 config.enable_rtp_data_channel = true;
2273 auto pc = CreatePeerConnection(config);
2274 pc->CreateDataChannel("dummy");
2275 auto offer = pc->CreateOffer();
2276 EXPECT_TRUE(pc->CreateOfferAndSetAsLocal());
2277 EXPECT_TRUE(pc->SetRemoteDescription(pc->CreateRollback()));
2278 EXPECT_TRUE(pc->SetLocalDescription(std::move(offer)));
2279 pc->pc()->Close();
2280 }
2281
2282 } // namespace webrtc
2283