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 <stddef.h>
12
13 #include <algorithm>
14 #include <map>
15 #include <memory>
16 #include <string>
17 #include <tuple>
18 #include <utility>
19 #include <vector>
20
21 #include "absl/strings/string_view.h"
22 #include "absl/types/optional.h"
23 #include "api/call/call_factory_interface.h"
24 #include "api/field_trials_view.h"
25 #include "api/jsep.h"
26 #include "api/media_stream_interface.h"
27 #include "api/media_types.h"
28 #include "api/peer_connection_interface.h"
29 #include "api/rtc_error.h"
30 #include "api/rtp_parameters.h"
31 #include "api/rtp_receiver_interface.h"
32 #include "api/rtp_sender_interface.h"
33 #include "api/rtp_transceiver_direction.h"
34 #include "api/rtp_transceiver_interface.h"
35 #include "api/scoped_refptr.h"
36 #include "api/task_queue/default_task_queue_factory.h"
37 #include "api/task_queue/task_queue_factory.h"
38 #include "api/transport/field_trial_based_config.h"
39 #include "api/transport/sctp_transport_factory_interface.h"
40 #include "media/base/media_engine.h"
41 #include "media/base/stream_params.h"
42 #include "media/engine/webrtc_media_engine.h"
43 #include "media/engine/webrtc_media_engine_defaults.h"
44 #include "modules/audio_device/include/audio_device.h"
45 #include "p2p/base/p2p_constants.h"
46 #include "p2p/base/port_allocator.h"
47 #include "p2p/base/transport_info.h"
48 #include "pc/channel_interface.h"
49 #include "pc/media_session.h"
50 #include "pc/peer_connection_wrapper.h"
51 #include "pc/sdp_utils.h"
52 #include "pc/session_description.h"
53 #include "pc/test/mock_peer_connection_observers.h"
54 #include "rtc_base/rtc_certificate_generator.h"
55 #include "rtc_base/thread.h"
56 #include "test/gtest.h"
57 #ifdef WEBRTC_ANDROID
58 #include "pc/test/android_test_initializer.h"
59 #endif
60 #include "pc/test/fake_audio_capture_module.h"
61 #include "rtc_base/virtual_socket_server.h"
62 #include "test/gmock.h"
63 #include "test/pc/sctp/fake_sctp_transport.h"
64
65 // This file contains tests that ensure the PeerConnection's implementation of
66 // CreateOffer/CreateAnswer/SetLocalDescription/SetRemoteDescription conform
67 // to the JavaScript Session Establishment Protocol (JSEP).
68 // For now these semantics are only available when configuring the
69 // PeerConnection with Unified Plan, but eventually that will be the default.
70
71 namespace webrtc {
72
73 using cricket::MediaContentDescription;
74 using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
75 using ::testing::Combine;
76 using ::testing::ElementsAre;
77 using ::testing::UnorderedElementsAre;
78 using ::testing::Values;
79
CreatePeerConnectionFactoryDependencies()80 PeerConnectionFactoryDependencies CreatePeerConnectionFactoryDependencies() {
81 PeerConnectionFactoryDependencies dependencies;
82 dependencies.worker_thread = rtc::Thread::Current();
83 dependencies.network_thread = rtc::Thread::Current();
84 dependencies.signaling_thread = rtc::Thread::Current();
85 dependencies.task_queue_factory = CreateDefaultTaskQueueFactory();
86 dependencies.trials = std::make_unique<FieldTrialBasedConfig>();
87 cricket::MediaEngineDependencies media_deps;
88 media_deps.task_queue_factory = dependencies.task_queue_factory.get();
89 media_deps.adm = FakeAudioCaptureModule::Create();
90 media_deps.trials = dependencies.trials.get();
91 SetMediaEngineDefaults(&media_deps);
92 dependencies.media_engine = cricket::CreateMediaEngine(std::move(media_deps));
93 dependencies.call_factory = CreateCallFactory();
94 dependencies.sctp_factory = std::make_unique<FakeSctpTransportFactory>();
95 return dependencies;
96 }
97
98 class PeerConnectionJsepTest : public ::testing::Test {
99 protected:
100 typedef std::unique_ptr<PeerConnectionWrapper> WrapperPtr;
101
PeerConnectionJsepTest()102 PeerConnectionJsepTest()
103 : vss_(new rtc::VirtualSocketServer()), main_(vss_.get()) {
104 #ifdef WEBRTC_ANDROID
105 InitializeAndroidObjects();
106 #endif
107 }
108
CreatePeerConnection()109 WrapperPtr CreatePeerConnection() {
110 RTCConfiguration config;
111 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
112 return CreatePeerConnection(config);
113 }
114
CreatePeerConnection(const RTCConfiguration & config)115 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
116 rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory =
117 CreateModularPeerConnectionFactory(
118 CreatePeerConnectionFactoryDependencies());
119 auto observer = std::make_unique<MockPeerConnectionObserver>();
120 auto result = pc_factory->CreatePeerConnectionOrError(
121 config, PeerConnectionDependencies(observer.get()));
122 if (!result.ok()) {
123 return nullptr;
124 }
125
126 observer->SetPeerConnectionInterface(result.value().get());
127 return std::make_unique<PeerConnectionWrapper>(
128 pc_factory, result.MoveValue(), std::move(observer));
129 }
130
131 std::unique_ptr<rtc::VirtualSocketServer> vss_;
132 rtc::AutoSocketServerThread main_;
133 };
134
135 // Tests for JSEP initial offer generation.
136
137 // Test that an offer created by a PeerConnection with no transceivers generates
138 // no media sections.
TEST_F(PeerConnectionJsepTest,EmptyInitialOffer)139 TEST_F(PeerConnectionJsepTest, EmptyInitialOffer) {
140 auto caller = CreatePeerConnection();
141
142 auto offer = caller->CreateOffer();
143 ASSERT_EQ(0u, offer->description()->contents().size());
144 }
145
146 // Test that an initial offer with one audio track generates one audio media
147 // section.
TEST_F(PeerConnectionJsepTest,AudioOnlyInitialOffer)148 TEST_F(PeerConnectionJsepTest, AudioOnlyInitialOffer) {
149 auto caller = CreatePeerConnection();
150 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
151
152 auto offer = caller->CreateOffer();
153 auto contents = offer->description()->contents();
154 ASSERT_EQ(1u, contents.size());
155 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, contents[0].media_description()->type());
156 }
157
158 // Test than an initial offer with one video track generates one video media
159 // section
TEST_F(PeerConnectionJsepTest,VideoOnlyInitialOffer)160 TEST_F(PeerConnectionJsepTest, VideoOnlyInitialOffer) {
161 auto caller = CreatePeerConnection();
162 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
163
164 auto offer = caller->CreateOffer();
165 auto contents = offer->description()->contents();
166 ASSERT_EQ(1u, contents.size());
167 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, contents[0].media_description()->type());
168 }
169
170 // Test that an initial offer with one data channel generates one data media
171 // section.
TEST_F(PeerConnectionJsepTest,DataOnlyInitialOffer)172 TEST_F(PeerConnectionJsepTest, DataOnlyInitialOffer) {
173 auto caller = CreatePeerConnection();
174 caller->CreateDataChannel("dc");
175
176 auto offer = caller->CreateOffer();
177 auto contents = offer->description()->contents();
178 ASSERT_EQ(1u, contents.size());
179 EXPECT_EQ(cricket::MEDIA_TYPE_DATA, contents[0].media_description()->type());
180 }
181
182 // Test that creating multiple data channels only results in one data section
183 // generated in the offer.
TEST_F(PeerConnectionJsepTest,MultipleDataChannelsCreateOnlyOneDataSection)184 TEST_F(PeerConnectionJsepTest, MultipleDataChannelsCreateOnlyOneDataSection) {
185 auto caller = CreatePeerConnection();
186 caller->CreateDataChannel("first");
187 caller->CreateDataChannel("second");
188 caller->CreateDataChannel("third");
189
190 auto offer = caller->CreateOffer();
191 ASSERT_EQ(1u, offer->description()->contents().size());
192 }
193
194 // Test that multiple media sections in the initial offer are ordered in the
195 // order the transceivers were added to the PeerConnection. This is required by
196 // JSEP section 5.2.1.
TEST_F(PeerConnectionJsepTest,MediaSectionsInInitialOfferOrderedCorrectly)197 TEST_F(PeerConnectionJsepTest, MediaSectionsInInitialOfferOrderedCorrectly) {
198 auto caller = CreatePeerConnection();
199 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
200 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
201 RtpTransceiverInit init;
202 init.direction = RtpTransceiverDirection::kSendOnly;
203 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init);
204
205 auto offer = caller->CreateOffer();
206 auto contents = offer->description()->contents();
207 ASSERT_EQ(3u, contents.size());
208
209 const MediaContentDescription* media_description1 =
210 contents[0].media_description();
211 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, media_description1->type());
212 EXPECT_EQ(RtpTransceiverDirection::kSendRecv,
213 media_description1->direction());
214
215 const MediaContentDescription* media_description2 =
216 contents[1].media_description();
217 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, media_description2->type());
218 EXPECT_EQ(RtpTransceiverDirection::kSendRecv,
219 media_description2->direction());
220
221 const MediaContentDescription* media_description3 =
222 contents[2].media_description();
223 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, media_description3->type());
224 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
225 media_description3->direction());
226 }
227
228 // Test that media sections in the initial offer have different mids.
TEST_F(PeerConnectionJsepTest,MediaSectionsInInitialOfferHaveDifferentMids)229 TEST_F(PeerConnectionJsepTest, MediaSectionsInInitialOfferHaveDifferentMids) {
230 auto caller = CreatePeerConnection();
231 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
232 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
233
234 auto offer = caller->CreateOffer();
235 auto contents = offer->description()->contents();
236 ASSERT_EQ(2u, contents.size());
237 EXPECT_NE(contents[0].name, contents[1].name);
238 }
239
TEST_F(PeerConnectionJsepTest,StoppedTransceiverHasNoMediaSectionInInitialOffer)240 TEST_F(PeerConnectionJsepTest,
241 StoppedTransceiverHasNoMediaSectionInInitialOffer) {
242 auto caller = CreatePeerConnection();
243 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
244 transceiver->StopInternal();
245
246 auto offer = caller->CreateOffer();
247 EXPECT_EQ(0u, offer->description()->contents().size());
248 }
249
250 // Tests for JSEP SetLocalDescription with a local offer.
251
TEST_F(PeerConnectionJsepTest,SetLocalEmptyOfferCreatesNoTransceivers)252 TEST_F(PeerConnectionJsepTest, SetLocalEmptyOfferCreatesNoTransceivers) {
253 auto caller = CreatePeerConnection();
254
255 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
256
257 EXPECT_THAT(caller->pc()->GetTransceivers(), ElementsAre());
258 EXPECT_THAT(caller->pc()->GetSenders(), ElementsAre());
259 EXPECT_THAT(caller->pc()->GetReceivers(), ElementsAre());
260 }
261
TEST_F(PeerConnectionJsepTest,SetLocalOfferSetsTransceiverMid)262 TEST_F(PeerConnectionJsepTest, SetLocalOfferSetsTransceiverMid) {
263 auto caller = CreatePeerConnection();
264 auto audio_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
265 auto video_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
266
267 auto offer = caller->CreateOffer();
268 std::string audio_mid = offer->description()->contents()[0].name;
269 std::string video_mid = offer->description()->contents()[1].name;
270
271 ASSERT_TRUE(caller->SetLocalDescription(std::move(offer)));
272
273 EXPECT_EQ(audio_mid, audio_transceiver->mid());
274 EXPECT_EQ(video_mid, video_transceiver->mid());
275 }
276
277 // Tests for JSEP SetRemoteDescription with a remote offer.
278
279 // Test that setting a remote offer with sendrecv audio and video creates two
280 // transceivers, one for receiving audio and one for receiving video.
TEST_F(PeerConnectionJsepTest,SetRemoteOfferCreatesTransceivers)281 TEST_F(PeerConnectionJsepTest, SetRemoteOfferCreatesTransceivers) {
282 auto caller = CreatePeerConnection();
283 auto caller_audio = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
284 auto caller_video = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
285 auto callee = CreatePeerConnection();
286
287 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
288
289 auto transceivers = callee->pc()->GetTransceivers();
290 ASSERT_EQ(2u, transceivers.size());
291
292 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, transceivers[0]->media_type());
293 EXPECT_EQ(caller_audio->mid(), transceivers[0]->mid());
294 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly, transceivers[0]->direction());
295 EXPECT_EQ(0u, transceivers[0]->sender()->stream_ids().size());
296
297 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, transceivers[1]->media_type());
298 EXPECT_EQ(caller_video->mid(), transceivers[1]->mid());
299 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly, transceivers[1]->direction());
300 EXPECT_EQ(0u, transceivers[1]->sender()->stream_ids().size());
301 }
302
303 // Test that setting a remote offer with an audio track will reuse the
304 // transceiver created for a local audio track added by AddTrack.
305 // This is specified in JSEP section 5.10 (Applying a Remote Description). The
306 // intent is to preserve backwards compatibility with clients who only use the
307 // AddTrack API.
TEST_F(PeerConnectionJsepTest,SetRemoteOfferReusesTransceiverFromAddTrack)308 TEST_F(PeerConnectionJsepTest, SetRemoteOfferReusesTransceiverFromAddTrack) {
309 auto caller = CreatePeerConnection();
310 caller->AddAudioTrack("a");
311 auto caller_audio = caller->pc()->GetTransceivers()[0];
312 auto callee = CreatePeerConnection();
313 callee->AddAudioTrack("a");
314
315 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
316
317 auto transceivers = callee->pc()->GetTransceivers();
318 ASSERT_EQ(1u, transceivers.size());
319 EXPECT_EQ(MediaStreamTrackInterface::kAudioKind,
320 transceivers[0]->receiver()->track()->kind());
321 EXPECT_EQ(caller_audio->mid(), transceivers[0]->mid());
322 }
323
324 // Test that setting a remote offer with an audio track marked sendonly will not
325 // reuse a transceiver created by AddTrack. JSEP only allows the transceiver to
326 // be reused if the offer direction is sendrecv or recvonly.
TEST_F(PeerConnectionJsepTest,SetRemoteOfferDoesNotReuseTransceiverIfDirectionSendOnly)327 TEST_F(PeerConnectionJsepTest,
328 SetRemoteOfferDoesNotReuseTransceiverIfDirectionSendOnly) {
329 auto caller = CreatePeerConnection();
330 caller->AddAudioTrack("a");
331 auto caller_audio = caller->pc()->GetTransceivers()[0];
332 caller_audio->SetDirectionWithError(RtpTransceiverDirection::kSendOnly);
333 auto callee = CreatePeerConnection();
334 callee->AddAudioTrack("a");
335
336 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
337
338 auto transceivers = callee->pc()->GetTransceivers();
339 ASSERT_EQ(2u, transceivers.size());
340 EXPECT_EQ(absl::nullopt, transceivers[0]->mid());
341 EXPECT_EQ(caller_audio->mid(), transceivers[1]->mid());
342 }
343
344 // Test that setting a remote offer with an audio track will not reuse a
345 // transceiver added by AddTransceiver. The logic for reusing a transceiver is
346 // specific to those added by AddTrack and is tested above.
TEST_F(PeerConnectionJsepTest,SetRemoteOfferDoesNotReuseTransceiverFromAddTransceiver)347 TEST_F(PeerConnectionJsepTest,
348 SetRemoteOfferDoesNotReuseTransceiverFromAddTransceiver) {
349 auto caller = CreatePeerConnection();
350 caller->AddAudioTrack("a");
351 auto callee = CreatePeerConnection();
352 auto transceiver = callee->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
353
354 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
355
356 auto transceivers = callee->pc()->GetTransceivers();
357 ASSERT_EQ(2u, transceivers.size());
358 EXPECT_EQ(absl::nullopt, transceivers[0]->mid());
359 EXPECT_EQ(caller->pc()->GetTransceivers()[0]->mid(), transceivers[1]->mid());
360 EXPECT_EQ(MediaStreamTrackInterface::kAudioKind,
361 transceivers[1]->receiver()->track()->kind());
362 }
363
364 // Test that setting a remote offer with an audio track will not reuse a
365 // transceiver created for a local video track added by AddTrack.
TEST_F(PeerConnectionJsepTest,SetRemoteOfferDoesNotReuseTransceiverOfWrongType)366 TEST_F(PeerConnectionJsepTest,
367 SetRemoteOfferDoesNotReuseTransceiverOfWrongType) {
368 auto caller = CreatePeerConnection();
369 caller->AddAudioTrack("a");
370 auto callee = CreatePeerConnection();
371 auto video_sender = callee->AddVideoTrack("v");
372
373 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
374
375 auto transceivers = callee->pc()->GetTransceivers();
376 ASSERT_EQ(2u, transceivers.size());
377 EXPECT_EQ(absl::nullopt, transceivers[0]->mid());
378 EXPECT_EQ(caller->pc()->GetTransceivers()[0]->mid(), transceivers[1]->mid());
379 EXPECT_EQ(MediaStreamTrackInterface::kAudioKind,
380 transceivers[1]->receiver()->track()->kind());
381 }
382
383 // Test that setting a remote offer with an audio track will not reuse a
384 // stopped transceiver.
TEST_F(PeerConnectionJsepTest,SetRemoteOfferDoesNotReuseStoppedTransceiver)385 TEST_F(PeerConnectionJsepTest, SetRemoteOfferDoesNotReuseStoppedTransceiver) {
386 auto caller = CreatePeerConnection();
387 caller->AddAudioTrack("a");
388 auto callee = CreatePeerConnection();
389 callee->AddAudioTrack("a");
390 callee->pc()->GetTransceivers()[0]->StopInternal();
391
392 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
393
394 auto transceivers = callee->pc()->GetTransceivers();
395 ASSERT_EQ(2u, transceivers.size());
396 // The stopped transceiver is removed in SetLocalDescription(answer)
397 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
398 transceivers = callee->pc()->GetTransceivers();
399 ASSERT_EQ(1u, transceivers.size());
400 EXPECT_EQ(caller->pc()->GetTransceivers()[0]->mid(), transceivers[0]->mid());
401 EXPECT_FALSE(transceivers[0]->stopped());
402 }
403
404 // Test that audio and video transceivers created on the remote side with
405 // AddTrack will all be reused if there is the same number of audio/video tracks
406 // in the remote offer. Additionally, this tests that transceivers are
407 // successfully matched even if they are in a different order on the remote
408 // side.
TEST_F(PeerConnectionJsepTest,SetRemoteOfferReusesTransceiversOfBothTypes)409 TEST_F(PeerConnectionJsepTest, SetRemoteOfferReusesTransceiversOfBothTypes) {
410 auto caller = CreatePeerConnection();
411 caller->AddVideoTrack("v");
412 caller->AddAudioTrack("a");
413 auto callee = CreatePeerConnection();
414 callee->AddAudioTrack("a");
415 callee->AddVideoTrack("v");
416
417 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
418
419 auto caller_transceivers = caller->pc()->GetTransceivers();
420 auto callee_transceivers = callee->pc()->GetTransceivers();
421 ASSERT_EQ(2u, callee_transceivers.size());
422 EXPECT_EQ(caller_transceivers[0]->mid(), callee_transceivers[1]->mid());
423 EXPECT_EQ(caller_transceivers[1]->mid(), callee_transceivers[0]->mid());
424 }
425
426 // Tests for JSEP initial CreateAnswer.
427
428 // Test that the answer to a remote offer creates media sections for each
429 // offered media in the same order and with the same mids.
TEST_F(PeerConnectionJsepTest,CreateAnswerHasSameMidsAsOffer)430 TEST_F(PeerConnectionJsepTest, CreateAnswerHasSameMidsAsOffer) {
431 auto caller = CreatePeerConnection();
432 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
433 auto second_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
434 auto third_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
435 caller->CreateDataChannel("dc");
436 auto callee = CreatePeerConnection();
437
438 auto offer = caller->CreateOffer();
439 const auto* offer_data = cricket::GetFirstDataContent(offer->description());
440 ASSERT_TRUE(
441 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
442 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
443
444 auto answer = callee->CreateAnswer();
445 auto contents = answer->description()->contents();
446 ASSERT_EQ(4u, contents.size());
447 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, contents[0].media_description()->type());
448 EXPECT_EQ(first_transceiver->mid(), contents[0].name);
449 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, contents[1].media_description()->type());
450 EXPECT_EQ(second_transceiver->mid(), contents[1].name);
451 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, contents[2].media_description()->type());
452 EXPECT_EQ(third_transceiver->mid(), contents[2].name);
453 EXPECT_EQ(cricket::MEDIA_TYPE_DATA, contents[3].media_description()->type());
454 EXPECT_EQ(offer_data->name, contents[3].name);
455 }
456
457 // Test that an answering media section is marked as rejected if the underlying
458 // transceiver has been stopped.
TEST_F(PeerConnectionJsepTest,CreateAnswerRejectsStoppedTransceiver)459 TEST_F(PeerConnectionJsepTest, CreateAnswerRejectsStoppedTransceiver) {
460 auto caller = CreatePeerConnection();
461 caller->AddAudioTrack("a");
462 auto callee = CreatePeerConnection();
463
464 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
465
466 callee->pc()->GetTransceivers()[0]->StopInternal();
467
468 auto answer = callee->CreateAnswer();
469 auto contents = answer->description()->contents();
470 ASSERT_EQ(1u, contents.size());
471 EXPECT_TRUE(contents[0].rejected);
472 }
473
474 // Test that CreateAnswer will generate media sections which will only send or
475 // receive if the offer indicates it can do the reciprocating direction.
476 // The full matrix is tested more extensively in MediaSession.
TEST_F(PeerConnectionJsepTest,CreateAnswerNegotiatesDirection)477 TEST_F(PeerConnectionJsepTest, CreateAnswerNegotiatesDirection) {
478 auto caller = CreatePeerConnection();
479 RtpTransceiverInit init;
480 init.direction = RtpTransceiverDirection::kSendOnly;
481 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init);
482 auto callee = CreatePeerConnection();
483 callee->AddAudioTrack("a");
484
485 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
486
487 auto answer = callee->CreateAnswer();
488 auto contents = answer->description()->contents();
489 ASSERT_EQ(1u, contents.size());
490 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
491 contents[0].media_description()->direction());
492 }
493
494 // Tests for JSEP SetLocalDescription with a local answer.
495 // Note that these test only the additional behaviors not covered by
496 // SetLocalDescription with a local offer.
497
498 // Test that SetLocalDescription with an answer sets the current_direction
499 // property of the transceivers mentioned in the session description.
TEST_F(PeerConnectionJsepTest,SetLocalAnswerUpdatesCurrentDirection)500 TEST_F(PeerConnectionJsepTest, SetLocalAnswerUpdatesCurrentDirection) {
501 auto caller = CreatePeerConnection();
502 auto caller_audio = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
503 caller_audio->SetDirectionWithError(RtpTransceiverDirection::kRecvOnly);
504 auto callee = CreatePeerConnection();
505 callee->AddAudioTrack("a");
506
507 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
508 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
509
510 auto transceivers = callee->pc()->GetTransceivers();
511 ASSERT_EQ(1u, transceivers.size());
512 // Since the offer was recvonly and the transceiver direction is sendrecv,
513 // the negotiated direction will be sendonly.
514 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
515 transceivers[0]->current_direction());
516 }
517
518 // Tests for JSEP SetRemoteDescription with a remote answer.
519 // Note that these test only the additional behaviors not covered by
520 // SetRemoteDescription with a remote offer.
521
TEST_F(PeerConnectionJsepTest,SetRemoteAnswerUpdatesCurrentDirection)522 TEST_F(PeerConnectionJsepTest, SetRemoteAnswerUpdatesCurrentDirection) {
523 auto caller = CreatePeerConnection();
524 caller->AddAudioTrack("a");
525 auto callee = CreatePeerConnection();
526 callee->AddAudioTrack("a");
527 auto callee_audio = callee->pc()->GetTransceivers()[0];
528 callee_audio->SetDirectionWithError(RtpTransceiverDirection::kSendOnly);
529
530 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
531 ASSERT_TRUE(
532 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
533
534 auto transceivers = caller->pc()->GetTransceivers();
535 ASSERT_EQ(1u, transceivers.size());
536 // Since the remote transceiver was set to sendonly, the negotiated direction
537 // in the answer would be sendonly which we apply as recvonly to the local
538 // transceiver.
539 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
540 transceivers[0]->current_direction());
541 }
542
TEST_F(PeerConnectionJsepTest,ChangeDirectionFromRecvOnlyToSendRecvDoesNotBreakVideoNegotiation)543 TEST_F(PeerConnectionJsepTest,
544 ChangeDirectionFromRecvOnlyToSendRecvDoesNotBreakVideoNegotiation) {
545 auto caller = CreatePeerConnection();
546 auto caller_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
547 auto callee = CreatePeerConnection();
548 caller_transceiver->SetDirectionWithError(RtpTransceiverDirection::kRecvOnly);
549
550 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
551 ASSERT_TRUE(
552 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
553
554 caller_transceiver->SetDirectionWithError(RtpTransceiverDirection::kSendRecv);
555
556 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
557 ASSERT_TRUE(
558 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
559 }
560
TEST_F(PeerConnectionJsepTest,ChangeDirectionFromRecvOnlyToSendRecvDoesNotBreakAudioNegotiation)561 TEST_F(PeerConnectionJsepTest,
562 ChangeDirectionFromRecvOnlyToSendRecvDoesNotBreakAudioNegotiation) {
563 auto caller = CreatePeerConnection();
564 auto caller_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
565 auto callee = CreatePeerConnection();
566 caller_transceiver->SetDirectionWithError(RtpTransceiverDirection::kRecvOnly);
567
568 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
569 ASSERT_TRUE(
570 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
571
572 caller_transceiver->SetDirectionWithError(RtpTransceiverDirection::kSendRecv);
573
574 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
575 ASSERT_TRUE(
576 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
577 }
578
579 // Tests for multiple round trips.
580
581 // Test that setting a transceiver with the inactive direction does not stop it
582 // on either the caller or the callee.
TEST_F(PeerConnectionJsepTest,SettingTransceiverInactiveDoesNotStopIt)583 TEST_F(PeerConnectionJsepTest, SettingTransceiverInactiveDoesNotStopIt) {
584 auto caller = CreatePeerConnection();
585 caller->AddAudioTrack("a");
586 auto callee = CreatePeerConnection();
587 callee->AddAudioTrack("a");
588 callee->pc()->GetTransceivers()[0]->SetDirectionWithError(
589 RtpTransceiverDirection::kInactive);
590
591 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
592 ASSERT_TRUE(
593 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
594
595 EXPECT_FALSE(caller->pc()->GetTransceivers()[0]->stopped());
596 EXPECT_FALSE(callee->pc()->GetTransceivers()[0]->stopped());
597 }
598
599 // Test that if a transceiver had been associated and later stopped, then a
600 // media section is still generated for it and the media section is marked as
601 // rejected.
TEST_F(PeerConnectionJsepTest,ReOfferMediaSectionForAssociatedStoppedTransceiverIsRejected)602 TEST_F(PeerConnectionJsepTest,
603 ReOfferMediaSectionForAssociatedStoppedTransceiverIsRejected) {
604 auto caller = CreatePeerConnection();
605 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
606 auto callee = CreatePeerConnection();
607
608 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
609 ASSERT_TRUE(
610 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
611
612 ASSERT_TRUE(transceiver->mid());
613 transceiver->StopInternal();
614
615 auto reoffer = caller->CreateOffer();
616 auto contents = reoffer->description()->contents();
617 ASSERT_EQ(1u, contents.size());
618 EXPECT_TRUE(contents[0].rejected);
619 }
620
621 // Test that stopping an associated transceiver on the caller side will stop the
622 // corresponding transceiver on the remote side when the remote offer is
623 // applied.
TEST_F(PeerConnectionJsepTest,StoppingTransceiverInOfferStopsTransceiverOnRemoteSide)624 TEST_F(PeerConnectionJsepTest,
625 StoppingTransceiverInOfferStopsTransceiverOnRemoteSide) {
626 auto caller = CreatePeerConnection();
627 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
628 auto callee = CreatePeerConnection();
629
630 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
631 ASSERT_TRUE(
632 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
633
634 transceiver->StopInternal();
635
636 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
637
638 auto transceivers = callee->pc()->GetTransceivers();
639 EXPECT_EQ(1u, transceivers.size());
640 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
641 transceivers = callee->pc()->GetTransceivers();
642 EXPECT_EQ(0u, transceivers.size());
643 }
644
645 // Test that CreateOffer will only generate a recycled media section if the
646 // transceiver to be recycled has been seen stopped by the other side first.
TEST_F(PeerConnectionJsepTest,CreateOfferDoesNotRecycleMediaSectionIfFirstStopped)647 TEST_F(PeerConnectionJsepTest,
648 CreateOfferDoesNotRecycleMediaSectionIfFirstStopped) {
649 auto caller = CreatePeerConnection();
650 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
651 auto callee = CreatePeerConnection();
652
653 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
654 ASSERT_TRUE(
655 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
656
657 auto second_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
658 first_transceiver->StopInternal();
659
660 auto reoffer = caller->CreateOffer();
661 auto contents = reoffer->description()->contents();
662 ASSERT_EQ(2u, contents.size());
663 EXPECT_TRUE(contents[0].rejected);
664 EXPECT_FALSE(contents[1].rejected);
665 }
666
667 // Test that the offer/answer and the transceivers are correctly generated and
668 // updated when the media section is recycled after the callee stops a
669 // transceiver and sends an answer with a 0 port.
TEST_F(PeerConnectionJsepTest,RecycleMediaSectionWhenStoppingTransceiverOnAnswerer)670 TEST_F(PeerConnectionJsepTest,
671 RecycleMediaSectionWhenStoppingTransceiverOnAnswerer) {
672 auto caller = CreatePeerConnection();
673 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
674 auto callee = CreatePeerConnection();
675
676 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
677 std::string first_mid = *first_transceiver->mid();
678 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
679 callee->pc()->GetTransceivers()[0]->StopInternal();
680 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
681 ASSERT_TRUE(
682 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
683 EXPECT_TRUE(first_transceiver->stopped());
684 // First transceivers are dissociated on caller side.
685 ASSERT_EQ(absl::nullopt, first_transceiver->mid());
686 // They are disassociated on callee side.
687 ASSERT_EQ(0u, callee->pc()->GetTransceivers().size());
688
689 // New offer exchange with new transceivers that recycles the m section
690 // correctly.
691 caller->AddAudioTrack("audio2");
692 callee->AddAudioTrack("audio2");
693 auto offer = caller->CreateOffer();
694 auto offer_contents = offer->description()->contents();
695 std::string second_mid = offer_contents[0].name;
696 ASSERT_EQ(1u, offer_contents.size());
697 EXPECT_FALSE(offer_contents[0].rejected);
698 EXPECT_NE(first_mid, second_mid);
699
700 // Setting the offer on each side will dissociate the first transceivers and
701 // associate the new transceivers.
702 ASSERT_TRUE(
703 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
704 EXPECT_EQ(absl::nullopt, first_transceiver->mid());
705 ASSERT_EQ(1u, caller->pc()->GetTransceivers().size());
706 EXPECT_EQ(second_mid, caller->pc()->GetTransceivers()[0]->mid());
707 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
708 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
709 EXPECT_EQ(second_mid, callee->pc()->GetTransceivers()[0]->mid());
710
711 // The new answer should also recycle the m section correctly.
712 auto answer = callee->CreateAnswer();
713 auto answer_contents = answer->description()->contents();
714 ASSERT_EQ(1u, answer_contents.size());
715 EXPECT_FALSE(answer_contents[0].rejected);
716 EXPECT_EQ(second_mid, answer_contents[0].name);
717
718 // Finishing the negotiation shouldn't add or dissociate any transceivers.
719 ASSERT_TRUE(
720 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
721 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
722 auto caller_transceivers = caller->pc()->GetTransceivers();
723 ASSERT_EQ(1u, caller_transceivers.size());
724 EXPECT_EQ(second_mid, caller_transceivers[0]->mid());
725 auto callee_transceivers = callee->pc()->GetTransceivers();
726 ASSERT_EQ(1u, callee_transceivers.size());
727 EXPECT_EQ(second_mid, callee_transceivers[0]->mid());
728 }
729
730 // Test that creating/setting a local offer that recycles an m= section is
731 // idempotent.
TEST_F(PeerConnectionJsepTest,CreateOfferRecyclesWhenOfferingTwice)732 TEST_F(PeerConnectionJsepTest, CreateOfferRecyclesWhenOfferingTwice) {
733 // Do a negotiation with a port 0 for the media section.
734 auto caller = CreatePeerConnection();
735 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
736 auto callee = CreatePeerConnection();
737 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
738 first_transceiver->StopInternal();
739 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
740 caller->AddAudioTrack("audio2");
741
742 // Create a new offer that recycles the media section and set it as a local
743 // description.
744 auto offer = caller->CreateOffer();
745 auto offer_contents = offer->description()->contents();
746 ASSERT_EQ(1u, offer_contents.size());
747 EXPECT_FALSE(offer_contents[0].rejected);
748 ASSERT_TRUE(caller->SetLocalDescription(std::move(offer)));
749 ASSERT_EQ(1u, caller->pc()->GetTransceivers().size());
750 EXPECT_FALSE(caller->pc()->GetTransceivers()[0]->stopped());
751 std::string second_mid = offer_contents[0].name;
752
753 // Create another new offer and set the local description again without the
754 // rest of any negotation ocurring.
755 auto second_offer = caller->CreateOffer();
756 auto second_offer_contents = second_offer->description()->contents();
757 ASSERT_EQ(1u, second_offer_contents.size());
758 EXPECT_FALSE(second_offer_contents[0].rejected);
759 // The mid shouldn't change.
760 EXPECT_EQ(second_mid, second_offer_contents[0].name);
761
762 ASSERT_TRUE(caller->SetLocalDescription(std::move(second_offer)));
763 // Make sure that the caller's transceivers are associated correctly.
764 auto caller_transceivers = caller->pc()->GetTransceivers();
765 ASSERT_EQ(1u, caller_transceivers.size());
766 EXPECT_EQ(second_mid, caller_transceivers[0]->mid());
767 EXPECT_FALSE(caller_transceivers[0]->stopped());
768 }
769
770 // Test that the offer/answer and transceivers for both the caller and callee
771 // side are generated/updated correctly when recycling an audio/video media
772 // section as a media section of either the same or opposite type.
773 // Correct recycling works as follows:
774 // - The m= section is re-offered with a new MID value and the new media type.
775 // - The previously-associated transceiver is dissociated when the new offer is
776 // set as a local description on the offerer or as a remote description on
777 // the answerer.
778 // - The new transceiver is associated with the new MID value.
779 class RecycleMediaSectionTest
780 : public PeerConnectionJsepTest,
781 public ::testing::WithParamInterface<
782 std::tuple<cricket::MediaType, cricket::MediaType>> {
783 protected:
RecycleMediaSectionTest()784 RecycleMediaSectionTest() {
785 first_type_ = std::get<0>(GetParam());
786 second_type_ = std::get<1>(GetParam());
787 }
788
789 cricket::MediaType first_type_;
790 cricket::MediaType second_type_;
791 };
792
793 // Test that recycling works properly when a new transceiver recycles an m=
794 // section that was rejected in both the current local and remote descriptions.
TEST_P(RecycleMediaSectionTest,CurrentLocalAndCurrentRemoteRejected)795 TEST_P(RecycleMediaSectionTest, CurrentLocalAndCurrentRemoteRejected) {
796 auto caller = CreatePeerConnection();
797 auto first_transceiver = caller->AddTransceiver(first_type_);
798 auto callee = CreatePeerConnection();
799
800 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
801
802 std::string first_mid = *first_transceiver->mid();
803 first_transceiver->StopInternal();
804
805 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
806
807 auto second_transceiver = caller->AddTransceiver(second_type_);
808
809 // The offer should reuse the previous media section but allocate a new MID
810 // and change the media type.
811 auto offer = caller->CreateOffer();
812 auto offer_contents = offer->description()->contents();
813 ASSERT_EQ(1u, offer_contents.size());
814 EXPECT_FALSE(offer_contents[0].rejected);
815 EXPECT_EQ(second_type_, offer_contents[0].media_description()->type());
816 std::string second_mid = offer_contents[0].name;
817 EXPECT_NE(first_mid, second_mid);
818
819 // Setting the local offer will dissociate the previous transceiver and set
820 // the MID for the new transceiver.
821 ASSERT_TRUE(
822 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
823 EXPECT_EQ(absl::nullopt, first_transceiver->mid());
824 EXPECT_EQ(second_mid, second_transceiver->mid());
825
826 // Setting the remote offer will dissociate the previous transceiver and
827 // create a new transceiver for the media section.
828 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
829 auto callee_transceivers = callee->pc()->GetTransceivers();
830 ASSERT_EQ(1u, callee_transceivers.size());
831 EXPECT_EQ(second_mid, callee_transceivers[0]->mid());
832 EXPECT_EQ(second_type_, callee_transceivers[0]->media_type());
833
834 // The answer should have only one media section for the new transceiver.
835 auto answer = callee->CreateAnswer();
836 auto answer_contents = answer->description()->contents();
837 ASSERT_EQ(1u, answer_contents.size());
838 EXPECT_FALSE(answer_contents[0].rejected);
839 EXPECT_EQ(second_mid, answer_contents[0].name);
840 EXPECT_EQ(second_type_, answer_contents[0].media_description()->type());
841
842 // Setting the local answer should succeed.
843 ASSERT_TRUE(
844 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
845
846 // Setting the remote answer should succeed and not create any new
847 // transceivers.
848 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
849 ASSERT_EQ(1u, caller->pc()->GetTransceivers().size());
850 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
851 }
852
853 // Test that recycling works properly when a new transceiver recycles an m=
854 // section that was rejected in only the current remote description.
TEST_P(RecycleMediaSectionTest,CurrentRemoteOnlyRejected)855 TEST_P(RecycleMediaSectionTest, CurrentRemoteOnlyRejected) {
856 auto caller = CreatePeerConnection();
857 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
858 auto callee = CreatePeerConnection();
859
860 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
861
862 std::string first_mid = *caller_first_transceiver->mid();
863 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
864 auto callee_first_transceiver = callee->pc()->GetTransceivers()[0];
865 callee_first_transceiver->StopInternal();
866
867 // The answer will have a rejected m= section.
868 ASSERT_TRUE(
869 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
870
871 // The offer should reuse the previous media section but allocate a new MID
872 // and change the media type.
873 auto caller_second_transceiver = caller->AddTransceiver(second_type_);
874 auto offer = caller->CreateOffer();
875 const auto& offer_contents = offer->description()->contents();
876 ASSERT_EQ(1u, offer_contents.size());
877 EXPECT_FALSE(offer_contents[0].rejected);
878 EXPECT_EQ(second_type_, offer_contents[0].media_description()->type());
879 std::string second_mid = offer_contents[0].name;
880 EXPECT_NE(first_mid, second_mid);
881
882 // Setting the local offer will dissociate the previous transceiver and set
883 // the MID for the new transceiver.
884 ASSERT_TRUE(
885 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
886 EXPECT_EQ(absl::nullopt, caller_first_transceiver->mid());
887 EXPECT_EQ(second_mid, caller_second_transceiver->mid());
888
889 // Setting the remote offer will dissociate the previous transceiver and
890 // create a new transceiver for the media section.
891 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
892 auto callee_transceivers = callee->pc()->GetTransceivers();
893 ASSERT_EQ(1u, callee_transceivers.size());
894 EXPECT_EQ(second_mid, callee_transceivers[0]->mid());
895 EXPECT_EQ(second_type_, callee_transceivers[0]->media_type());
896
897 // The answer should have only one media section for the new transceiver.
898 auto answer = callee->CreateAnswer();
899 auto answer_contents = answer->description()->contents();
900 ASSERT_EQ(1u, answer_contents.size());
901 EXPECT_FALSE(answer_contents[0].rejected);
902 EXPECT_EQ(second_mid, answer_contents[0].name);
903 EXPECT_EQ(second_type_, answer_contents[0].media_description()->type());
904
905 // Setting the local answer should succeed.
906 ASSERT_TRUE(
907 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
908
909 // Setting the remote answer should succeed and not create any new
910 // transceivers.
911 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
912 ASSERT_EQ(1u, caller->pc()->GetTransceivers().size());
913 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
914 }
915
916 // Test that recycling works properly when a new transceiver recycles an m=
917 // section that was rejected only in the current local description.
TEST_P(RecycleMediaSectionTest,CurrentLocalOnlyRejected)918 TEST_P(RecycleMediaSectionTest, CurrentLocalOnlyRejected) {
919 auto caller = CreatePeerConnection();
920 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
921 auto callee = CreatePeerConnection();
922
923 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
924
925 std::string first_mid = *caller_first_transceiver->mid();
926 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
927 auto callee_first_transceiver = callee->pc()->GetTransceivers()[0];
928 callee_first_transceiver->StopInternal();
929
930 // The answer will have a rejected m= section.
931 ASSERT_TRUE(
932 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
933
934 // The offer should reuse the previous media section but allocate a new MID
935 // and change the media type.
936 auto callee_second_transceiver = callee->AddTransceiver(second_type_);
937 auto offer = callee->CreateOffer();
938 const auto& offer_contents = offer->description()->contents();
939 ASSERT_EQ(1u, offer_contents.size());
940 EXPECT_FALSE(offer_contents[0].rejected);
941 EXPECT_EQ(second_type_, offer_contents[0].media_description()->type());
942 std::string second_mid = offer_contents[0].name;
943 EXPECT_NE(first_mid, second_mid);
944
945 // Setting the local offer will dissociate the previous transceiver and set
946 // the MID for the new transceiver.
947 ASSERT_TRUE(
948 callee->SetLocalDescription(CloneSessionDescription(offer.get())));
949 EXPECT_EQ(absl::nullopt, callee_first_transceiver->mid());
950 EXPECT_EQ(second_mid, callee_second_transceiver->mid());
951
952 // Setting the remote offer will dissociate the previous transceiver and
953 // create a new transceiver for the media section.
954 ASSERT_TRUE(caller->SetRemoteDescription(std::move(offer)));
955 auto caller_transceivers = caller->pc()->GetTransceivers();
956 ASSERT_EQ(1u, caller_transceivers.size());
957 EXPECT_EQ(second_mid, caller_transceivers[0]->mid());
958 EXPECT_EQ(second_type_, caller_transceivers[0]->media_type());
959
960 // The answer should have only one media section for the new transceiver.
961 auto answer = caller->CreateAnswer();
962 auto answer_contents = answer->description()->contents();
963 ASSERT_EQ(1u, answer_contents.size());
964 EXPECT_FALSE(answer_contents[0].rejected);
965 EXPECT_EQ(second_mid, answer_contents[0].name);
966 EXPECT_EQ(second_type_, answer_contents[0].media_description()->type());
967
968 // Setting the local answer should succeed.
969 ASSERT_TRUE(
970 caller->SetLocalDescription(CloneSessionDescription(answer.get())));
971
972 // Setting the remote answer should succeed and not create any new
973 // transceivers.
974 ASSERT_TRUE(callee->SetRemoteDescription(std::move(answer)));
975 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
976 ASSERT_EQ(1u, caller->pc()->GetTransceivers().size());
977 }
978
979 // Test that a m= section is *not* recycled if the media section is only
980 // rejected in the pending local description and there is no current remote
981 // description.
TEST_P(RecycleMediaSectionTest,PendingLocalRejectedAndNoRemote)982 TEST_P(RecycleMediaSectionTest, PendingLocalRejectedAndNoRemote) {
983 auto caller = CreatePeerConnection();
984 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
985
986 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
987
988 std::string first_mid = *caller_first_transceiver->mid();
989 caller_first_transceiver->StopInternal();
990
991 // The reoffer will have a rejected m= section.
992 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
993
994 auto caller_second_transceiver = caller->AddTransceiver(second_type_);
995
996 // The reoffer should not recycle the existing m= section since it is not
997 // rejected in either the *current* local or *current* remote description.
998 auto reoffer = caller->CreateOffer();
999 auto reoffer_contents = reoffer->description()->contents();
1000 ASSERT_EQ(2u, reoffer_contents.size());
1001 EXPECT_TRUE(reoffer_contents[0].rejected);
1002 EXPECT_EQ(first_type_, reoffer_contents[0].media_description()->type());
1003 EXPECT_EQ(first_mid, reoffer_contents[0].name);
1004 EXPECT_FALSE(reoffer_contents[1].rejected);
1005 EXPECT_EQ(second_type_, reoffer_contents[1].media_description()->type());
1006 std::string second_mid = reoffer_contents[1].name;
1007 EXPECT_NE(first_mid, second_mid);
1008
1009 ASSERT_TRUE(caller->SetLocalDescription(std::move(reoffer)));
1010
1011 // Both RtpTransceivers are associated.
1012 EXPECT_EQ(first_mid, caller_first_transceiver->mid());
1013 EXPECT_EQ(second_mid, caller_second_transceiver->mid());
1014 }
1015
1016 // Test that a m= section is *not* recycled if the media section is only
1017 // rejected in the pending local description and not rejected in the current
1018 // remote description.
TEST_P(RecycleMediaSectionTest,PendingLocalRejectedAndNotRejectedRemote)1019 TEST_P(RecycleMediaSectionTest, PendingLocalRejectedAndNotRejectedRemote) {
1020 auto caller = CreatePeerConnection();
1021 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
1022 auto callee = CreatePeerConnection();
1023
1024 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1025
1026 std::string first_mid = *caller_first_transceiver->mid();
1027 caller_first_transceiver->StopInternal();
1028
1029 // The reoffer will have a rejected m= section.
1030 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
1031
1032 auto caller_second_transceiver = caller->AddTransceiver(second_type_);
1033
1034 // The reoffer should not recycle the existing m= section since it is not
1035 // rejected in either the *current* local or *current* remote description.
1036 auto reoffer = caller->CreateOffer();
1037 auto reoffer_contents = reoffer->description()->contents();
1038 ASSERT_EQ(2u, reoffer_contents.size());
1039 EXPECT_TRUE(reoffer_contents[0].rejected);
1040 EXPECT_EQ(first_type_, reoffer_contents[0].media_description()->type());
1041 EXPECT_EQ(first_mid, reoffer_contents[0].name);
1042 EXPECT_FALSE(reoffer_contents[1].rejected);
1043 EXPECT_EQ(second_type_, reoffer_contents[1].media_description()->type());
1044 std::string second_mid = reoffer_contents[1].name;
1045 EXPECT_NE(first_mid, second_mid);
1046
1047 ASSERT_TRUE(caller->SetLocalDescription(std::move(reoffer)));
1048
1049 // Both RtpTransceivers are associated.
1050 EXPECT_EQ(first_mid, caller_first_transceiver->mid());
1051 EXPECT_EQ(second_mid, caller_second_transceiver->mid());
1052 }
1053
1054 // Test that an m= section is *not* recycled if the media section is only
1055 // rejected in the pending remote description and there is no current local
1056 // description.
TEST_P(RecycleMediaSectionTest,PendingRemoteRejectedAndNoLocal)1057 TEST_P(RecycleMediaSectionTest, PendingRemoteRejectedAndNoLocal) {
1058 auto caller = CreatePeerConnection();
1059 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
1060 auto callee = CreatePeerConnection();
1061
1062 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1063
1064 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
1065 auto callee_first_transceiver = callee->pc()->GetTransceivers()[0];
1066 std::string first_mid = *callee_first_transceiver->mid();
1067 caller_first_transceiver->StopInternal();
1068
1069 // The reoffer will have a rejected m= section.
1070 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1071
1072 auto callee_second_transceiver = callee->AddTransceiver(second_type_);
1073
1074 // The reoffer should not recycle the existing m= section since it is not
1075 // rejected in either the *current* local or *current* remote description.
1076 auto reoffer = callee->CreateOffer();
1077 auto reoffer_contents = reoffer->description()->contents();
1078 ASSERT_EQ(2u, reoffer_contents.size());
1079 EXPECT_TRUE(reoffer_contents[0].rejected);
1080 EXPECT_EQ(first_type_, reoffer_contents[0].media_description()->type());
1081 EXPECT_EQ(first_mid, reoffer_contents[0].name);
1082 EXPECT_FALSE(reoffer_contents[1].rejected);
1083 EXPECT_EQ(second_type_, reoffer_contents[1].media_description()->type());
1084 std::string second_mid = reoffer_contents[1].name;
1085 EXPECT_NE(first_mid, second_mid);
1086
1087 // Note: Cannot actually set the reoffer since the callee is in the signaling
1088 // state 'have-remote-offer'.
1089 }
1090
1091 // Test that an m= section is *not* recycled if the media section is only
1092 // rejected in the pending remote description and not rejected in the current
1093 // local description.
TEST_P(RecycleMediaSectionTest,PendingRemoteRejectedAndNotRejectedLocal)1094 TEST_P(RecycleMediaSectionTest, PendingRemoteRejectedAndNotRejectedLocal) {
1095 auto caller = CreatePeerConnection();
1096 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
1097 auto callee = CreatePeerConnection();
1098
1099 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1100
1101 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
1102 auto callee_first_transceiver = callee->pc()->GetTransceivers()[0];
1103 std::string first_mid = *callee_first_transceiver->mid();
1104 caller_first_transceiver->StopInternal();
1105
1106 // The reoffer will have a rejected m= section.
1107 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1108
1109 auto callee_second_transceiver = callee->AddTransceiver(second_type_);
1110
1111 // The reoffer should not recycle the existing m= section since it is not
1112 // rejected in either the *current* local or *current* remote description.
1113 auto reoffer = callee->CreateOffer();
1114 auto reoffer_contents = reoffer->description()->contents();
1115 ASSERT_EQ(2u, reoffer_contents.size());
1116 EXPECT_TRUE(reoffer_contents[0].rejected);
1117 EXPECT_EQ(first_type_, reoffer_contents[0].media_description()->type());
1118 EXPECT_EQ(first_mid, reoffer_contents[0].name);
1119 EXPECT_FALSE(reoffer_contents[1].rejected);
1120 EXPECT_EQ(second_type_, reoffer_contents[1].media_description()->type());
1121 std::string second_mid = reoffer_contents[1].name;
1122 EXPECT_NE(first_mid, second_mid);
1123
1124 // Note: Cannot actually set the reoffer since the callee is in the signaling
1125 // state 'have-remote-offer'.
1126 }
1127
1128 // Test all combinations of audio and video as the first and second media type
1129 // for the media section. This is needed for full test coverage because
1130 // MediaSession has separate functions for processing audio and video media
1131 // sections.
1132 INSTANTIATE_TEST_SUITE_P(
1133 PeerConnectionJsepTest,
1134 RecycleMediaSectionTest,
1135 Combine(Values(cricket::MEDIA_TYPE_AUDIO, cricket::MEDIA_TYPE_VIDEO),
1136 Values(cricket::MEDIA_TYPE_AUDIO, cricket::MEDIA_TYPE_VIDEO)));
1137
1138 // Test that a new data channel section will not reuse a recycleable audio or
1139 // video media section. Additionally, tests that the new section is added to the
1140 // end of the session description.
TEST_F(PeerConnectionJsepTest,DataChannelDoesNotRecycleMediaSection)1141 TEST_F(PeerConnectionJsepTest, DataChannelDoesNotRecycleMediaSection) {
1142 auto caller = CreatePeerConnection();
1143 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1144 auto callee = CreatePeerConnection();
1145
1146 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1147
1148 transceiver->StopInternal();
1149
1150 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1151
1152 caller->CreateDataChannel("dc");
1153
1154 auto offer = caller->CreateOffer();
1155 auto offer_contents = offer->description()->contents();
1156 ASSERT_EQ(2u, offer_contents.size());
1157 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO,
1158 offer_contents[0].media_description()->type());
1159 EXPECT_EQ(cricket::MEDIA_TYPE_DATA,
1160 offer_contents[1].media_description()->type());
1161
1162 ASSERT_TRUE(
1163 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
1164 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1165
1166 auto answer = callee->CreateAnswer();
1167 auto answer_contents = answer->description()->contents();
1168 ASSERT_EQ(2u, answer_contents.size());
1169 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO,
1170 answer_contents[0].media_description()->type());
1171 EXPECT_EQ(cricket::MEDIA_TYPE_DATA,
1172 answer_contents[1].media_description()->type());
1173 }
1174
1175 // Test that if a new track is added to an existing session that has a data,
1176 // the new section comes at the end of the new offer, after the existing data
1177 // section.
TEST_F(PeerConnectionJsepTest,AudioTrackAddedAfterDataSectionInReoffer)1178 TEST_F(PeerConnectionJsepTest, AudioTrackAddedAfterDataSectionInReoffer) {
1179 auto caller = CreatePeerConnection();
1180 caller->CreateDataChannel("dc");
1181 auto callee = CreatePeerConnection();
1182
1183 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1184
1185 caller->AddAudioTrack("a");
1186
1187 auto offer = caller->CreateOffer();
1188 auto contents = offer->description()->contents();
1189 ASSERT_EQ(2u, contents.size());
1190 EXPECT_EQ(cricket::MEDIA_TYPE_DATA, contents[0].media_description()->type());
1191 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, contents[1].media_description()->type());
1192 }
1193
1194 // Tests for MID properties.
1195
RenameSection(size_t mline_index,const std::string & new_mid,SessionDescriptionInterface * sdesc)1196 static void RenameSection(size_t mline_index,
1197 const std::string& new_mid,
1198 SessionDescriptionInterface* sdesc) {
1199 cricket::SessionDescription* desc = sdesc->description();
1200 std::string old_mid = desc->contents()[mline_index].name;
1201 desc->contents()[mline_index].name = new_mid;
1202 desc->transport_infos()[mline_index].content_name = new_mid;
1203 const cricket::ContentGroup* bundle =
1204 desc->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1205 if (bundle) {
1206 cricket::ContentGroup new_bundle = *bundle;
1207 if (new_bundle.RemoveContentName(old_mid)) {
1208 new_bundle.AddContentName(new_mid);
1209 }
1210 desc->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1211 desc->AddGroup(new_bundle);
1212 }
1213 }
1214
1215 // Test that two PeerConnections can have a successful offer/answer exchange if
1216 // the MIDs are changed from the defaults.
TEST_F(PeerConnectionJsepTest,OfferAnswerWithChangedMids)1217 TEST_F(PeerConnectionJsepTest, OfferAnswerWithChangedMids) {
1218 constexpr char kFirstMid[] = "nondefaultmid";
1219 constexpr char kSecondMid[] = "randommid";
1220
1221 auto caller = CreatePeerConnection();
1222 caller->AddAudioTrack("a");
1223 caller->AddAudioTrack("b");
1224 auto callee = CreatePeerConnection();
1225
1226 auto offer = caller->CreateOffer();
1227 RenameSection(0, kFirstMid, offer.get());
1228 RenameSection(1, kSecondMid, offer.get());
1229
1230 ASSERT_TRUE(
1231 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
1232 auto caller_transceivers = caller->pc()->GetTransceivers();
1233 EXPECT_EQ(kFirstMid, caller_transceivers[0]->mid());
1234 EXPECT_EQ(kSecondMid, caller_transceivers[1]->mid());
1235
1236 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1237 auto callee_transceivers = callee->pc()->GetTransceivers();
1238 EXPECT_EQ(kFirstMid, callee_transceivers[0]->mid());
1239 EXPECT_EQ(kSecondMid, callee_transceivers[1]->mid());
1240
1241 auto answer = callee->CreateAnswer();
1242 auto answer_contents = answer->description()->contents();
1243 EXPECT_EQ(kFirstMid, answer_contents[0].name);
1244 EXPECT_EQ(kSecondMid, answer_contents[1].name);
1245
1246 ASSERT_TRUE(
1247 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
1248 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
1249 }
1250
1251 // Test that CreateOffer will generate a MID that is not already used if the
1252 // default it would have picked is already taken. This is tested by using a
1253 // third PeerConnection to determine what the default would be for the second
1254 // media section then setting that as the first media section's MID.
TEST_F(PeerConnectionJsepTest,CreateOfferGeneratesUniqueMidIfAlreadyTaken)1255 TEST_F(PeerConnectionJsepTest, CreateOfferGeneratesUniqueMidIfAlreadyTaken) {
1256 // First, find what the default MID is for the second media section.
1257 auto pc = CreatePeerConnection();
1258 pc->AddAudioTrack("a");
1259 pc->AddAudioTrack("b");
1260 auto default_offer = pc->CreateOffer();
1261 std::string default_second_mid =
1262 default_offer->description()->contents()[1].name;
1263
1264 // Now, do an offer/answer with one track which has the MID set to the default
1265 // second MID.
1266 auto caller = CreatePeerConnection();
1267 caller->AddAudioTrack("a");
1268 auto callee = CreatePeerConnection();
1269
1270 auto offer = caller->CreateOffer();
1271 RenameSection(0, default_second_mid, offer.get());
1272
1273 ASSERT_TRUE(
1274 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
1275 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1276 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1277
1278 // Add a second track and ensure that the MID is different.
1279 caller->AddAudioTrack("b");
1280
1281 auto reoffer = caller->CreateOffer();
1282 auto reoffer_contents = reoffer->description()->contents();
1283 EXPECT_EQ(default_second_mid, reoffer_contents[0].name);
1284 EXPECT_NE(reoffer_contents[0].name, reoffer_contents[1].name);
1285 }
1286
1287 // Test that if an audio or video section has the default data section MID, then
1288 // CreateOffer will generate a unique MID for the newly added data section.
TEST_F(PeerConnectionJsepTest,CreateOfferGeneratesUniqueMidForDataSectionIfAlreadyTaken)1289 TEST_F(PeerConnectionJsepTest,
1290 CreateOfferGeneratesUniqueMidForDataSectionIfAlreadyTaken) {
1291 // First, find what the default MID is for the data channel.
1292 auto pc = CreatePeerConnection();
1293 pc->CreateDataChannel("dc");
1294 auto default_offer = pc->CreateOffer();
1295 std::string default_data_mid =
1296 default_offer->description()->contents()[0].name;
1297
1298 // Now do an offer/answer with one audio track which has a MID set to the
1299 // default data MID.
1300 auto caller = CreatePeerConnection();
1301 caller->AddAudioTrack("a");
1302 auto callee = CreatePeerConnection();
1303
1304 auto offer = caller->CreateOffer();
1305 RenameSection(0, default_data_mid, offer.get());
1306
1307 ASSERT_TRUE(
1308 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
1309 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1310 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1311
1312 // Add a data channel and ensure that the MID is different.
1313 caller->CreateDataChannel("dc");
1314
1315 auto reoffer = caller->CreateOffer();
1316 auto reoffer_contents = reoffer->description()->contents();
1317 EXPECT_EQ(default_data_mid, reoffer_contents[0].name);
1318 EXPECT_NE(reoffer_contents[0].name, reoffer_contents[1].name);
1319 }
1320
1321 // Test that a reoffer initiated by the callee adds a new track to the caller.
TEST_F(PeerConnectionJsepTest,CalleeDoesReoffer)1322 TEST_F(PeerConnectionJsepTest, CalleeDoesReoffer) {
1323 auto caller = CreatePeerConnection();
1324 caller->AddAudioTrack("a");
1325 auto callee = CreatePeerConnection();
1326 callee->AddAudioTrack("a");
1327 callee->AddVideoTrack("v");
1328
1329 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1330
1331 EXPECT_EQ(1u, caller->pc()->GetTransceivers().size());
1332 EXPECT_EQ(2u, callee->pc()->GetTransceivers().size());
1333
1334 ASSERT_TRUE(callee->ExchangeOfferAnswerWith(caller.get()));
1335
1336 EXPECT_EQ(2u, caller->pc()->GetTransceivers().size());
1337 EXPECT_EQ(2u, callee->pc()->GetTransceivers().size());
1338 }
1339
1340 // Tests for MSID properties.
1341
1342 // Test that adding a track with AddTrack results in an offer that signals the
1343 // track's ID.
TEST_F(PeerConnectionJsepTest,AddingTrackWithAddTrackSpecifiesTrackId)1344 TEST_F(PeerConnectionJsepTest, AddingTrackWithAddTrackSpecifiesTrackId) {
1345 const std::string kTrackId = "audio_track";
1346
1347 auto caller = CreatePeerConnection();
1348 caller->AddAudioTrack(kTrackId);
1349
1350 auto offer = caller->CreateOffer();
1351 auto contents = offer->description()->contents();
1352 ASSERT_EQ(1u, contents.size());
1353 auto streams = contents[0].media_description()->streams();
1354 ASSERT_EQ(1u, streams.size());
1355 EXPECT_EQ(kTrackId, streams[0].id);
1356 }
1357
1358 // Test that adding a track by calling AddTransceiver then SetTrack results in
1359 // an offer that does not signal the track's ID and signals a random ID.
TEST_F(PeerConnectionJsepTest,AddingTrackWithAddTransceiverSpecifiesRandomTrackId)1360 TEST_F(PeerConnectionJsepTest,
1361 AddingTrackWithAddTransceiverSpecifiesRandomTrackId) {
1362 const std::string kTrackId = "audio_track";
1363
1364 auto caller = CreatePeerConnection();
1365 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1366 transceiver->sender()->SetTrack(caller->CreateAudioTrack(kTrackId).get());
1367
1368 auto offer = caller->CreateOffer();
1369 auto contents = offer->description()->contents();
1370 ASSERT_EQ(1u, contents.size());
1371 auto streams = contents[0].media_description()->streams();
1372 ASSERT_EQ(1u, streams.size());
1373 EXPECT_NE(kTrackId, streams[0].id);
1374 }
1375
1376 // Test that if the transceiver is recvonly or inactive, then no MSID
1377 // information is included in the offer.
TEST_F(PeerConnectionJsepTest,NoMsidInOfferIfTransceiverDirectionHasNoSend)1378 TEST_F(PeerConnectionJsepTest, NoMsidInOfferIfTransceiverDirectionHasNoSend) {
1379 auto caller = CreatePeerConnection();
1380
1381 RtpTransceiverInit init_recvonly;
1382 init_recvonly.direction = RtpTransceiverDirection::kRecvOnly;
1383 ASSERT_TRUE(caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init_recvonly));
1384
1385 RtpTransceiverInit init_inactive;
1386 init_inactive.direction = RtpTransceiverDirection::kInactive;
1387 ASSERT_TRUE(caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init_inactive));
1388
1389 auto offer = caller->CreateOffer();
1390 auto contents = offer->description()->contents();
1391 ASSERT_EQ(2u, contents.size());
1392 // MSID is specified in the first stream, so no streams means no MSID.
1393 EXPECT_EQ(0u, contents[0].media_description()->streams().size());
1394 EXPECT_EQ(0u, contents[1].media_description()->streams().size());
1395 }
1396
1397 // Test that if an answer negotiates transceiver directions of recvonly or
1398 // inactive, then no MSID information is included in the answer.
TEST_F(PeerConnectionJsepTest,NoMsidInAnswerIfNoRespondingTracks)1399 TEST_F(PeerConnectionJsepTest, NoMsidInAnswerIfNoRespondingTracks) {
1400 auto caller = CreatePeerConnection();
1401 auto callee = CreatePeerConnection();
1402
1403 // recvonly transceiver will get negotiated to inactive since the callee has
1404 // no tracks to send in response.
1405 RtpTransceiverInit init_recvonly;
1406 init_recvonly.direction = RtpTransceiverDirection::kRecvOnly;
1407 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init_recvonly);
1408
1409 // sendrecv transceiver will get negotiated to recvonly since the callee has
1410 // no tracks to send in response.
1411 RtpTransceiverInit init_sendrecv;
1412 init_sendrecv.direction = RtpTransceiverDirection::kSendRecv;
1413 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init_sendrecv);
1414
1415 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1416
1417 auto answer = callee->CreateAnswer();
1418 auto contents = answer->description()->contents();
1419 ASSERT_EQ(2u, contents.size());
1420 // MSID is specified in the first stream, so no streams means no MSID.
1421 EXPECT_EQ(0u, contents[0].media_description()->streams().size());
1422 EXPECT_EQ(0u, contents[1].media_description()->streams().size());
1423 }
1424
1425 // Test that the MSID is included even if the transceiver direction has changed
1426 // to inactive if the transceiver had previously sent media.
TEST_F(PeerConnectionJsepTest,IncludeMsidEvenIfDirectionHasChanged)1427 TEST_F(PeerConnectionJsepTest, IncludeMsidEvenIfDirectionHasChanged) {
1428 auto caller = CreatePeerConnection();
1429 caller->AddAudioTrack("audio");
1430 auto callee = CreatePeerConnection();
1431 callee->AddAudioTrack("audio");
1432
1433 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1434
1435 caller->pc()->GetTransceivers()[0]->SetDirectionWithError(
1436 RtpTransceiverDirection::kInactive);
1437
1438 // The transceiver direction on both sides will turn to inactive.
1439 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1440
1441 auto* offer = callee->pc()->remote_description();
1442 auto offer_contents = offer->description()->contents();
1443 ASSERT_EQ(1u, offer_contents.size());
1444 // MSID is specified in the first stream. If it is present, assume that MSID
1445 // is there.
1446 EXPECT_EQ(1u, offer_contents[0].media_description()->streams().size());
1447
1448 auto* answer = caller->pc()->remote_description();
1449 auto answer_contents = answer->description()->contents();
1450 ASSERT_EQ(1u, answer_contents.size());
1451 EXPECT_EQ(1u, answer_contents[0].media_description()->streams().size());
1452 }
1453
1454 // Test that stopping a RtpTransceiver will cause future offers to not include
1455 // any MSID information for that section.
TEST_F(PeerConnectionJsepTest,RemoveMsidIfTransceiverStopped)1456 TEST_F(PeerConnectionJsepTest, RemoveMsidIfTransceiverStopped) {
1457 auto caller = CreatePeerConnection();
1458 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1459 auto callee = CreatePeerConnection();
1460
1461 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1462
1463 transceiver->StopInternal();
1464
1465 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1466
1467 auto* offer = callee->pc()->remote_description();
1468 auto offer_contents = offer->description()->contents();
1469 ASSERT_EQ(1u, offer_contents.size());
1470 // MSID is specified in the first stream, so no streams means no MSID.
1471 EXPECT_EQ(0u, offer_contents[0].media_description()->streams().size());
1472 }
1473
1474 // Test that the callee RtpReceiver created by a call to SetRemoteDescription
1475 // has its ID set to the signaled track ID.
TEST_F(PeerConnectionJsepTest,RtpReceiverCreatedBySetRemoteDescriptionHasSignaledTrackId)1476 TEST_F(PeerConnectionJsepTest,
1477 RtpReceiverCreatedBySetRemoteDescriptionHasSignaledTrackId) {
1478 const std::string kTrackId = "audio_track";
1479
1480 auto caller = CreatePeerConnection();
1481 auto callee = CreatePeerConnection();
1482 caller->AddAudioTrack(kTrackId);
1483
1484 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1485
1486 ASSERT_EQ(1u, callee->pc()->GetReceivers().size());
1487 auto receiver = callee->pc()->GetReceivers()[0];
1488 EXPECT_EQ(kTrackId, receiver->id());
1489 }
1490
1491 // Test that if the callee RtpReceiver is reused by a call to
1492 // SetRemoteDescription, its ID does not change.
TEST_F(PeerConnectionJsepTest,RtpReceiverCreatedBeforeSetRemoteDescriptionKeepsId)1493 TEST_F(PeerConnectionJsepTest,
1494 RtpReceiverCreatedBeforeSetRemoteDescriptionKeepsId) {
1495 const std::string kTrackId = "audio_track";
1496
1497 auto caller = CreatePeerConnection();
1498 auto callee = CreatePeerConnection();
1499 caller->AddAudioTrack(kTrackId);
1500 callee->AddAudioTrack("dummy_track");
1501
1502 ASSERT_EQ(1u, callee->pc()->GetReceivers().size());
1503 auto receiver = callee->pc()->GetReceivers()[0];
1504 std::string receiver_id = receiver->id();
1505
1506 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1507
1508 EXPECT_EQ(receiver_id, receiver->id());
1509 }
1510
1511 // Test that setting a remote offer with one track that has no streams fires off
1512 // the correct OnAddTrack event.
TEST_F(PeerConnectionJsepTest,SetRemoteOfferWithOneTrackNoStreamFiresOnAddTrack)1513 TEST_F(PeerConnectionJsepTest,
1514 SetRemoteOfferWithOneTrackNoStreamFiresOnAddTrack) {
1515 const std::string kTrackLabel = "audio_track";
1516
1517 auto caller = CreatePeerConnection();
1518 auto callee = CreatePeerConnection();
1519 ASSERT_TRUE(caller->AddAudioTrack(kTrackLabel));
1520
1521 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1522
1523 const auto& track_events = callee->observer()->add_track_events_;
1524 ASSERT_EQ(1u, track_events.size());
1525 const auto& event = track_events[0];
1526 EXPECT_EQ(kTrackLabel, event.receiver->track()->id());
1527 EXPECT_EQ(0u, event.streams.size());
1528 }
1529
1530 // Test that setting a remote offer with one track that has one stream fires off
1531 // the correct OnAddTrack event.
TEST_F(PeerConnectionJsepTest,SetRemoteOfferWithOneTrackOneStreamFiresOnAddTrack)1532 TEST_F(PeerConnectionJsepTest,
1533 SetRemoteOfferWithOneTrackOneStreamFiresOnAddTrack) {
1534 const std::string kTrackLabel = "audio_track";
1535 const std::string kStreamId = "audio_stream";
1536
1537 auto caller = CreatePeerConnection();
1538 auto callee = CreatePeerConnection();
1539 ASSERT_TRUE(caller->AddAudioTrack(kTrackLabel, {kStreamId}));
1540
1541 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1542
1543 const auto& track_events = callee->observer()->add_track_events_;
1544 ASSERT_EQ(1u, track_events.size());
1545 const auto& event = track_events[0];
1546 ASSERT_EQ(1u, event.streams.size());
1547 auto stream = event.streams[0];
1548 EXPECT_EQ(kStreamId, stream->id());
1549 EXPECT_THAT(track_events[0].snapshotted_stream_tracks.at(stream),
1550 ElementsAre(event.receiver->track()));
1551 EXPECT_EQ(event.receiver->streams(), track_events[0].streams);
1552 }
1553
1554 // Test that setting a remote offer with two tracks that share the same stream
1555 // fires off two OnAddTrack events, both with the same stream that has both
1556 // tracks present at the time of firing. This is to ensure that track events are
1557 // not fired until SetRemoteDescription has finished processing all the media
1558 // sections.
TEST_F(PeerConnectionJsepTest,SetRemoteOfferWithTwoTracksSameStreamFiresOnAddTrack)1559 TEST_F(PeerConnectionJsepTest,
1560 SetRemoteOfferWithTwoTracksSameStreamFiresOnAddTrack) {
1561 const std::string kTrack1Label = "audio_track1";
1562 const std::string kTrack2Label = "audio_track2";
1563 const std::string kSharedStreamId = "stream";
1564
1565 auto caller = CreatePeerConnection();
1566 auto callee = CreatePeerConnection();
1567 ASSERT_TRUE(caller->AddAudioTrack(kTrack1Label, {kSharedStreamId}));
1568 ASSERT_TRUE(caller->AddAudioTrack(kTrack2Label, {kSharedStreamId}));
1569
1570 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1571
1572 const auto& track_events = callee->observer()->add_track_events_;
1573 ASSERT_EQ(2u, track_events.size());
1574 const auto& event1 = track_events[0];
1575 const auto& event2 = track_events[1];
1576 ASSERT_EQ(1u, event1.streams.size());
1577 auto stream = event1.streams[0];
1578 ASSERT_THAT(event2.streams, ElementsAre(stream));
1579 auto track1 = event1.receiver->track();
1580 auto track2 = event2.receiver->track();
1581 EXPECT_THAT(event1.snapshotted_stream_tracks.at(stream),
1582 UnorderedElementsAre(track1, track2));
1583 EXPECT_THAT(event2.snapshotted_stream_tracks.at(stream),
1584 UnorderedElementsAre(track1, track2));
1585 }
1586
1587 // Test that setting a remote offer with one track that has two streams fires
1588 // off the correct OnAddTrack event.
TEST_F(PeerConnectionJsepTest,SetRemoteOfferWithOneTrackTwoStreamFiresOnAddTrack)1589 TEST_F(PeerConnectionJsepTest,
1590 SetRemoteOfferWithOneTrackTwoStreamFiresOnAddTrack) {
1591 const std::string kTrackLabel = "audio_track";
1592 const std::string kStreamId1 = "audio_stream1";
1593 const std::string kStreamId2 = "audio_stream2";
1594
1595 auto caller = CreatePeerConnection();
1596 auto callee = CreatePeerConnection();
1597 ASSERT_TRUE(caller->AddAudioTrack(kTrackLabel, {kStreamId1, kStreamId2}));
1598
1599 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1600
1601 const auto& track_events = callee->observer()->add_track_events_;
1602 ASSERT_EQ(1u, track_events.size());
1603 const auto& event = track_events[0];
1604 ASSERT_EQ(2u, event.streams.size());
1605 EXPECT_EQ(kStreamId1, event.streams[0]->id());
1606 EXPECT_EQ(kStreamId2, event.streams[1]->id());
1607 }
1608
1609 // Test that if an RtpTransceiver with a current_direction set is stopped, then
1610 // current_direction is changed to null.
TEST_F(PeerConnectionJsepTest,CurrentDirectionResetWhenRtpTransceiverStopped)1611 TEST_F(PeerConnectionJsepTest, CurrentDirectionResetWhenRtpTransceiverStopped) {
1612 auto caller = CreatePeerConnection();
1613 auto callee = CreatePeerConnection();
1614
1615 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1616
1617 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1618
1619 ASSERT_TRUE(transceiver->current_direction());
1620 transceiver->StopInternal();
1621 EXPECT_EQ(transceiver->current_direction(),
1622 RtpTransceiverDirection::kStopped);
1623 }
1624
1625 // Test that you can't set an answer on a PeerConnection before setting the
1626 // offer.
TEST_F(PeerConnectionJsepTest,AnswerBeforeOfferFails)1627 TEST_F(PeerConnectionJsepTest, AnswerBeforeOfferFails) {
1628 auto caller = CreatePeerConnection();
1629 auto callee = CreatePeerConnection();
1630 caller->AddAudioTrack("audio");
1631
1632 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1633
1634 RTCError error;
1635 ASSERT_FALSE(caller->SetRemoteDescription(callee->CreateAnswer(), &error));
1636 EXPECT_EQ(RTCErrorType::INVALID_STATE, error.type());
1637 }
1638
1639 // Test that a Unified Plan PeerConnection fails to set a Plan B offer if it has
1640 // two video tracks.
TEST_F(PeerConnectionJsepTest,TwoVideoPlanBToUnifiedPlanFails)1641 TEST_F(PeerConnectionJsepTest, TwoVideoPlanBToUnifiedPlanFails) {
1642 RTCConfiguration config_planb;
1643 config_planb.sdp_semantics = SdpSemantics::kPlanB_DEPRECATED;
1644 auto caller = CreatePeerConnection(config_planb);
1645 auto callee = CreatePeerConnection();
1646 caller->AddVideoTrack("video1");
1647 caller->AddVideoTrack("video2");
1648
1649 RTCError error;
1650 ASSERT_FALSE(callee->SetRemoteDescription(caller->CreateOffer(), &error));
1651 EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, error.type());
1652 }
1653
1654 // Test that a Unified Plan PeerConnection fails to set a Plan B answer if it
1655 // has two video tracks.
TEST_F(PeerConnectionJsepTest,OneVideoUnifiedPlanToTwoVideoPlanBFails)1656 TEST_F(PeerConnectionJsepTest, OneVideoUnifiedPlanToTwoVideoPlanBFails) {
1657 auto caller = CreatePeerConnection();
1658 RTCConfiguration config_planb;
1659 config_planb.sdp_semantics = SdpSemantics::kPlanB_DEPRECATED;
1660 auto callee = CreatePeerConnection(config_planb);
1661 caller->AddVideoTrack("video");
1662 callee->AddVideoTrack("video1");
1663 callee->AddVideoTrack("video2");
1664
1665 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1666
1667 RTCError error;
1668 ASSERT_FALSE(caller->SetRemoteDescription(caller->CreateAnswer(), &error));
1669 EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, error.type());
1670 }
1671
1672 // Removes the RTP header extension associated with the given URI from the media
1673 // description.
RemoveRtpHeaderExtensionByUri(MediaContentDescription * media_description,absl::string_view uri)1674 static void RemoveRtpHeaderExtensionByUri(
1675 MediaContentDescription* media_description,
1676 absl::string_view uri) {
1677 std::vector<RtpExtension> header_extensions =
1678 media_description->rtp_header_extensions();
1679 header_extensions.erase(std::remove_if(
1680 header_extensions.begin(), header_extensions.end(),
1681 [uri](const RtpExtension& extension) { return extension.uri == uri; }));
1682 media_description->set_rtp_header_extensions(header_extensions);
1683 }
1684
1685 // Transforms a session description to emulate a legacy endpoint which does not
1686 // support a=mid, BUNDLE, and the MID header extension.
ClearMids(SessionDescriptionInterface * sdesc)1687 static void ClearMids(SessionDescriptionInterface* sdesc) {
1688 cricket::SessionDescription* desc = sdesc->description();
1689 desc->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1690 cricket::ContentInfo* audio_content = cricket::GetFirstAudioContent(desc);
1691 if (audio_content) {
1692 desc->GetTransportInfoByName(audio_content->name)->content_name = "";
1693 audio_content->name = "";
1694 RemoveRtpHeaderExtensionByUri(audio_content->media_description(),
1695 RtpExtension::kMidUri);
1696 }
1697 cricket::ContentInfo* video_content = cricket::GetFirstVideoContent(desc);
1698 if (video_content) {
1699 desc->GetTransportInfoByName(video_content->name)->content_name = "";
1700 video_content->name = "";
1701 RemoveRtpHeaderExtensionByUri(video_content->media_description(),
1702 RtpExtension::kMidUri);
1703 }
1704 }
1705
1706 // Test that negotiation works with legacy endpoints which do not support a=mid.
TEST_F(PeerConnectionJsepTest,LegacyNoMidAudioOnlyOffer)1707 TEST_F(PeerConnectionJsepTest, LegacyNoMidAudioOnlyOffer) {
1708 auto caller = CreatePeerConnection();
1709 caller->AddAudioTrack("audio");
1710 auto callee = CreatePeerConnection();
1711 callee->AddAudioTrack("audio");
1712
1713 auto offer = caller->CreateOffer();
1714 ClearMids(offer.get());
1715
1716 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1717 EXPECT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1718 }
TEST_F(PeerConnectionJsepTest,LegacyNoMidAudioVideoOffer)1719 TEST_F(PeerConnectionJsepTest, LegacyNoMidAudioVideoOffer) {
1720 auto caller = CreatePeerConnection();
1721 caller->AddAudioTrack("audio");
1722 caller->AddVideoTrack("video");
1723 auto callee = CreatePeerConnection();
1724 callee->AddAudioTrack("audio");
1725 callee->AddVideoTrack("video");
1726
1727 auto offer = caller->CreateOffer();
1728 ClearMids(offer.get());
1729
1730 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1731 EXPECT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1732 }
TEST_F(PeerConnectionJsepTest,LegacyNoMidAudioOnlyAnswer)1733 TEST_F(PeerConnectionJsepTest, LegacyNoMidAudioOnlyAnswer) {
1734 auto caller = CreatePeerConnection();
1735 caller->AddAudioTrack("audio");
1736 auto callee = CreatePeerConnection();
1737 callee->AddAudioTrack("audio");
1738
1739 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1740
1741 auto answer = callee->CreateAnswer();
1742 ClearMids(answer.get());
1743
1744 EXPECT_TRUE(caller->SetRemoteDescription(std::move(answer)));
1745 }
TEST_F(PeerConnectionJsepTest,LegacyNoMidAudioVideoAnswer)1746 TEST_F(PeerConnectionJsepTest, LegacyNoMidAudioVideoAnswer) {
1747 auto caller = CreatePeerConnection();
1748 caller->AddAudioTrack("audio");
1749 caller->AddVideoTrack("video");
1750 auto callee = CreatePeerConnection();
1751 callee->AddAudioTrack("audio");
1752 callee->AddVideoTrack("video");
1753
1754 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1755
1756 auto answer = callee->CreateAnswer();
1757 ClearMids(answer.get());
1758
1759 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
1760 }
1761
1762 // Test that negotiation works with legacy endpoints which do not support a=mid
1763 // when setting two remote descriptions without setting a local description in
1764 // between.
TEST_F(PeerConnectionJsepTest,LegacyNoMidTwoRemoteOffers)1765 TEST_F(PeerConnectionJsepTest, LegacyNoMidTwoRemoteOffers) {
1766 auto caller = CreatePeerConnection();
1767 caller->AddAudioTrack("audio");
1768 auto callee = CreatePeerConnection();
1769 callee->AddAudioTrack("audio");
1770
1771 auto offer = caller->CreateOffer();
1772 ClearMids(offer.get());
1773
1774 ASSERT_TRUE(
1775 callee->SetRemoteDescription(CloneSessionDescription(offer.get())));
1776 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1777 EXPECT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1778 }
1779
1780 // Test that SetLocalDescription fails if a=mid lines are missing.
TEST_F(PeerConnectionJsepTest,SetLocalDescriptionFailsMissingMid)1781 TEST_F(PeerConnectionJsepTest, SetLocalDescriptionFailsMissingMid) {
1782 auto caller = CreatePeerConnection();
1783 caller->AddAudioTrack("audio");
1784
1785 auto offer = caller->CreateOffer();
1786 ClearMids(offer.get());
1787
1788 std::string error;
1789 ASSERT_FALSE(caller->SetLocalDescription(std::move(offer), &error));
1790 EXPECT_EQ(
1791 "Failed to set local offer sdp: A media section is missing a MID "
1792 "attribute.",
1793 error);
1794 }
1795
TEST_F(PeerConnectionJsepTest,RollbackSupportedInUnifiedPlan)1796 TEST_F(PeerConnectionJsepTest, RollbackSupportedInUnifiedPlan) {
1797 RTCConfiguration config;
1798 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
1799 config.enable_implicit_rollback = true;
1800 auto caller = CreatePeerConnection(config);
1801 auto callee = CreatePeerConnection(config);
1802 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
1803 EXPECT_TRUE(caller->SetLocalDescription(caller->CreateRollback()));
1804 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
1805 EXPECT_TRUE(caller->SetRemoteDescription(caller->CreateRollback()));
1806 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
1807 EXPECT_TRUE(caller->SetRemoteDescription(callee->CreateOffer()));
1808 }
1809
TEST_F(PeerConnectionJsepTest,RollbackNotSupportedInPlanB)1810 TEST_F(PeerConnectionJsepTest, RollbackNotSupportedInPlanB) {
1811 RTCConfiguration config;
1812 config.sdp_semantics = SdpSemantics::kPlanB_DEPRECATED;
1813 config.enable_implicit_rollback = true;
1814 auto caller = CreatePeerConnection(config);
1815 auto callee = CreatePeerConnection(config);
1816 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
1817 EXPECT_FALSE(caller->SetLocalDescription(caller->CreateRollback()));
1818 EXPECT_FALSE(caller->SetRemoteDescription(caller->CreateRollback()));
1819 EXPECT_FALSE(caller->SetRemoteDescription(callee->CreateOffer()));
1820 }
1821
TEST_F(PeerConnectionJsepTest,RollbackFailsInStableState)1822 TEST_F(PeerConnectionJsepTest, RollbackFailsInStableState) {
1823 auto caller = CreatePeerConnection();
1824 EXPECT_FALSE(caller->SetLocalDescription(caller->CreateRollback()));
1825 EXPECT_FALSE(caller->SetRemoteDescription(caller->CreateRollback()));
1826 }
1827
TEST_F(PeerConnectionJsepTest,RollbackToStableStateAndClearLocalOffer)1828 TEST_F(PeerConnectionJsepTest, RollbackToStableStateAndClearLocalOffer) {
1829 auto caller = CreatePeerConnection();
1830 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
1831 EXPECT_TRUE(caller->SetLocalDescription(caller->CreateRollback()));
1832 EXPECT_EQ(caller->signaling_state(), PeerConnectionInterface::kStable);
1833 EXPECT_EQ(caller->pc()->pending_local_description(), nullptr);
1834
1835 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
1836 EXPECT_TRUE(caller->SetRemoteDescription(caller->CreateRollback()));
1837 EXPECT_EQ(caller->signaling_state(), PeerConnectionInterface::kStable);
1838 EXPECT_EQ(caller->pc()->pending_local_description(), nullptr);
1839 }
1840
TEST_F(PeerConnectionJsepTest,RollbackToStableStateAndClearRemoteOffer)1841 TEST_F(PeerConnectionJsepTest, RollbackToStableStateAndClearRemoteOffer) {
1842 auto caller = CreatePeerConnection();
1843 auto callee = CreatePeerConnection();
1844 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1845 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
1846 EXPECT_EQ(callee->signaling_state(), PeerConnectionInterface::kStable);
1847 EXPECT_EQ(callee->pc()->pending_remote_description(), nullptr);
1848
1849 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1850 EXPECT_TRUE(callee->SetLocalDescription(caller->CreateRollback()));
1851 EXPECT_EQ(callee->signaling_state(), PeerConnectionInterface::kStable);
1852 EXPECT_EQ(callee->pc()->pending_remote_description(), nullptr);
1853 }
1854
TEST_F(PeerConnectionJsepTest,RollbackImplicitly)1855 TEST_F(PeerConnectionJsepTest, RollbackImplicitly) {
1856 RTCConfiguration config;
1857 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
1858 config.enable_implicit_rollback = true;
1859 auto caller = CreatePeerConnection(config);
1860 auto callee = CreatePeerConnection(config);
1861 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
1862 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1863 EXPECT_EQ(callee->signaling_state(),
1864 PeerConnectionInterface::kHaveRemoteOffer);
1865 EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal());
1866 EXPECT_FALSE(callee->observer()->legacy_renegotiation_needed());
1867 EXPECT_FALSE(callee->observer()->has_negotiation_needed_event());
1868 }
1869
TEST_F(PeerConnectionJsepTest,RollbackImplicitlyNegotatiationNotNeeded)1870 TEST_F(PeerConnectionJsepTest, RollbackImplicitlyNegotatiationNotNeeded) {
1871 RTCConfiguration config;
1872 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
1873 config.enable_implicit_rollback = true;
1874 auto caller = CreatePeerConnection(config);
1875 auto callee = CreatePeerConnection(config);
1876 caller->AddAudioTrack("a");
1877 callee->AddAudioTrack("b");
1878 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
1879 callee->observer()->clear_legacy_renegotiation_needed();
1880 callee->observer()->clear_latest_negotiation_needed_event();
1881 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1882 EXPECT_EQ(callee->signaling_state(),
1883 PeerConnectionInterface::kHaveRemoteOffer);
1884 EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal());
1885 // No negotiation needed as track got attached in the answer.
1886 EXPECT_FALSE(callee->observer()->legacy_renegotiation_needed());
1887 EXPECT_FALSE(callee->observer()->has_negotiation_needed_event());
1888 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 0u);
1889 }
1890
TEST_F(PeerConnectionJsepTest,RollbackImplicitlyAndNegotiationNeeded)1891 TEST_F(PeerConnectionJsepTest, RollbackImplicitlyAndNegotiationNeeded) {
1892 RTCConfiguration config;
1893 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
1894 config.enable_implicit_rollback = true;
1895 auto caller = CreatePeerConnection(config);
1896 auto callee = CreatePeerConnection(config);
1897 callee->AddAudioTrack("a");
1898 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
1899 callee->observer()->clear_legacy_renegotiation_needed();
1900 callee->observer()->clear_latest_negotiation_needed_event();
1901 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1902 EXPECT_EQ(callee->signaling_state(),
1903 PeerConnectionInterface::kHaveRemoteOffer);
1904 EXPECT_FALSE(callee->observer()->legacy_renegotiation_needed());
1905 EXPECT_FALSE(callee->observer()->has_negotiation_needed_event());
1906 EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal());
1907 EXPECT_TRUE(callee->observer()->legacy_renegotiation_needed());
1908 EXPECT_TRUE(callee->observer()->has_negotiation_needed_event());
1909 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 0u);
1910 }
1911
TEST_F(PeerConnectionJsepTest,AttemptToRollbackImplicitly)1912 TEST_F(PeerConnectionJsepTest, AttemptToRollbackImplicitly) {
1913 RTCConfiguration config;
1914 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
1915 config.enable_implicit_rollback = true;
1916 auto caller = CreatePeerConnection(config);
1917 auto callee = CreatePeerConnection(config);
1918 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
1919 EXPECT_FALSE(callee->SetRemoteDescription(
1920 CreateSessionDescription(SdpType::kOffer, "invalid sdp")));
1921 EXPECT_EQ(callee->signaling_state(),
1922 PeerConnectionInterface::kHaveLocalOffer);
1923 }
1924
TEST_F(PeerConnectionJsepTest,RollbackRemovesTransceiver)1925 TEST_F(PeerConnectionJsepTest, RollbackRemovesTransceiver) {
1926 auto caller = CreatePeerConnection();
1927 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1928 auto callee = CreatePeerConnection();
1929 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1930 ASSERT_EQ(callee->pc()->GetTransceivers().size(), 1u);
1931 auto transceiver = callee->pc()->GetTransceivers()[0];
1932 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
1933 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 0u);
1934 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 1u);
1935 // The removed transceiver should be stopped and its receiver track should be
1936 // ended.
1937 EXPECT_TRUE(transceiver->stopping());
1938 EXPECT_TRUE(transceiver->stopping());
1939 EXPECT_EQ(transceiver->receiver()->track()->state(),
1940 MediaStreamTrackInterface::kEnded);
1941 }
1942
TEST_F(PeerConnectionJsepTest,RollbackKeepsTransceiverAndClearsMid)1943 TEST_F(PeerConnectionJsepTest, RollbackKeepsTransceiverAndClearsMid) {
1944 auto caller = CreatePeerConnection();
1945 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1946 auto callee = CreatePeerConnection();
1947 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1948 callee->AddAudioTrack("a");
1949 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
1950 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
1951 // Transceiver can't be removed as track was added to it.
1952 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
1953 // Mid got cleared to make it reusable.
1954 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), absl::nullopt);
1955 // Transceiver should be counted as addTrack-created after rollback.
1956 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1957 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
1958 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 1u);
1959 // Because the transceiver is reusable, it must not be stopped and its
1960 // receiver track must still be live.
1961 auto transceiver = callee->pc()->GetTransceivers()[0];
1962 EXPECT_FALSE(transceiver->stopping());
1963 EXPECT_FALSE(transceiver->stopping());
1964 EXPECT_EQ(transceiver->receiver()->track()->state(),
1965 MediaStreamTrackInterface::kLive);
1966 }
1967
TEST_F(PeerConnectionJsepTest,RollbackKeepsTransceiverAfterAddTrackEvenWhenTrackIsNulled)1968 TEST_F(PeerConnectionJsepTest,
1969 RollbackKeepsTransceiverAfterAddTrackEvenWhenTrackIsNulled) {
1970 auto caller = CreatePeerConnection();
1971 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1972 auto callee = CreatePeerConnection();
1973 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1974 callee->AddAudioTrack("a");
1975 callee->pc()->GetTransceivers()[0]->sender()->SetTrack(nullptr);
1976 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->sender()->track(), nullptr);
1977 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
1978 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
1979 // Transceiver can't be removed as track was added to it.
1980 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
1981 // Mid got cleared to make it reusable.
1982 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), absl::nullopt);
1983 // Transceiver should be counted as addTrack-created after rollback.
1984 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1985 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
1986 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 1u);
1987 }
1988
TEST_F(PeerConnectionJsepTest,RollbackRestoresMid)1989 TEST_F(PeerConnectionJsepTest, RollbackRestoresMid) {
1990 auto caller = CreatePeerConnection();
1991 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1992 auto callee = CreatePeerConnection();
1993 callee->AddAudioTrack("a");
1994 auto offer = callee->CreateOffer();
1995 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1996 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
1997 EXPECT_NE(callee->pc()->GetTransceivers()[0]->mid(), absl::nullopt);
1998 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
1999 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), absl::nullopt);
2000 EXPECT_TRUE(callee->SetLocalDescription(std::move(offer)));
2001 }
2002
TEST_F(PeerConnectionJsepTest,RollbackRestoresInitSendEncodings)2003 TEST_F(PeerConnectionJsepTest, RollbackRestoresInitSendEncodings) {
2004 auto caller = CreatePeerConnection();
2005 RtpTransceiverInit init;
2006 init.direction = RtpTransceiverDirection::kSendRecv;
2007 RtpEncodingParameters encoding;
2008 encoding.rid = "hi";
2009 init.send_encodings.push_back(encoding);
2010 encoding.rid = "mid";
2011 init.send_encodings.push_back(encoding);
2012 encoding.rid = "lo";
2013 init.send_encodings.push_back(encoding);
2014 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init);
2015 auto encodings =
2016 caller->pc()->GetTransceivers()[0]->sender()->init_send_encodings();
2017 EXPECT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
2018 EXPECT_NE(caller->pc()->GetTransceivers()[0]->sender()->init_send_encodings(),
2019 encodings);
2020 EXPECT_TRUE(caller->SetLocalDescription(caller->CreateRollback()));
2021 EXPECT_EQ(caller->pc()->GetTransceivers()[0]->sender()->init_send_encodings(),
2022 encodings);
2023 }
2024
TEST_F(PeerConnectionJsepTest,RollbackDoesNotAffectSendEncodings)2025 TEST_F(PeerConnectionJsepTest, RollbackDoesNotAffectSendEncodings) {
2026 auto caller = CreatePeerConnection();
2027 auto callee = CreatePeerConnection();
2028 RtpTransceiverInit init;
2029 init.direction = RtpTransceiverDirection::kSendOnly;
2030 RtpEncodingParameters encoding;
2031 encoding.rid = "hi";
2032 init.send_encodings.push_back(encoding);
2033 encoding.rid = "mid";
2034 init.send_encodings.push_back(encoding);
2035 encoding.rid = "lo";
2036 init.send_encodings.push_back(encoding);
2037 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init);
2038 callee->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2039 callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal());
2040 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal());
2041 auto params = caller->pc()->GetTransceivers()[0]->sender()->GetParameters();
2042 EXPECT_TRUE(params.encodings[0].active);
2043 params.encodings[0].active = false;
2044 caller->pc()->GetTransceivers()[0]->sender()->SetParameters(params);
2045 auto offer = caller->CreateOffer();
2046 std::string offer_string;
2047 EXPECT_TRUE(offer.get()->ToString(&offer_string));
2048 std::string simulcast_line =
2049 offer_string.substr(offer_string.find("a=simulcast"));
2050 EXPECT_FALSE(simulcast_line.empty());
2051 EXPECT_TRUE(caller->SetLocalDescription(std::move(offer)));
2052 EXPECT_TRUE(caller->SetLocalDescription(caller->CreateRollback()));
2053 EXPECT_FALSE(caller->pc()
2054 ->GetTransceivers()[0]
2055 ->sender()
2056 ->GetParameters()
2057 .encodings[0]
2058 .active);
2059 offer = caller->CreateOffer();
2060 EXPECT_TRUE(offer.get()->ToString(&offer_string));
2061 EXPECT_EQ(offer_string.substr(offer_string.find("a=simulcast")),
2062 simulcast_line);
2063 }
2064
TEST_F(PeerConnectionJsepTest,RollbackRestoresMidAndRemovesTransceiver)2065 TEST_F(PeerConnectionJsepTest, RollbackRestoresMidAndRemovesTransceiver) {
2066 auto callee = CreatePeerConnection();
2067 callee->AddVideoTrack("a");
2068 auto offer = callee->CreateOffer();
2069 auto caller = CreatePeerConnection();
2070 caller->AddAudioTrack("b");
2071 caller->AddVideoTrack("c");
2072 auto mid = callee->pc()->GetTransceivers()[0]->mid();
2073 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2074 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 2u);
2075 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
2076 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
2077 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), mid);
2078 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->media_type(),
2079 cricket::MEDIA_TYPE_VIDEO);
2080 EXPECT_TRUE(callee->SetLocalDescription(std::move(offer)));
2081 EXPECT_EQ(callee->observer()->remove_track_events_.size(),
2082 callee->observer()->add_track_events_.size());
2083 }
2084
TEST_F(PeerConnectionJsepTest,RollbackHasNoEffectOnStableTransceivers)2085 TEST_F(PeerConnectionJsepTest, RollbackHasNoEffectOnStableTransceivers) {
2086 auto callee = CreatePeerConnection();
2087 callee->AddVideoTrack("a");
2088 auto caller = CreatePeerConnection();
2089 caller->AddAudioTrack("b");
2090 caller->AddVideoTrack("c");
2091 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2092 EXPECT_TRUE(
2093 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
2094 // In stable don't add or remove anything.
2095 callee->observer()->clear_legacy_renegotiation_needed();
2096 callee->observer()->clear_latest_negotiation_needed_event();
2097 size_t transceiver_count = callee->pc()->GetTransceivers().size();
2098 auto mid_0 = callee->pc()->GetTransceivers()[0]->mid();
2099 auto mid_1 = callee->pc()->GetTransceivers()[1]->mid();
2100 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2101 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
2102 EXPECT_EQ(callee->pc()->GetTransceivers().size(), transceiver_count);
2103 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), mid_0);
2104 EXPECT_EQ(callee->pc()->GetTransceivers()[1]->mid(), mid_1);
2105 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 0u);
2106 EXPECT_FALSE(callee->observer()->legacy_renegotiation_needed());
2107 EXPECT_FALSE(callee->observer()->has_negotiation_needed_event());
2108 }
2109
TEST_F(PeerConnectionJsepTest,ImplicitlyRollbackTransceiversWithSameMids)2110 TEST_F(PeerConnectionJsepTest, ImplicitlyRollbackTransceiversWithSameMids) {
2111 RTCConfiguration config;
2112 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
2113 config.enable_implicit_rollback = true;
2114 auto caller = CreatePeerConnection(config);
2115 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2116 auto callee = CreatePeerConnection(config);
2117 callee->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2118 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2119 auto initial_mid = callee->pc()->GetTransceivers()[0]->mid();
2120 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2121 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 2u);
2122 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), absl::nullopt);
2123 EXPECT_EQ(callee->pc()->GetTransceivers()[1]->mid(),
2124 caller->pc()->GetTransceivers()[0]->mid());
2125 EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal()); // Go to stable.
2126 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2127 EXPECT_NE(callee->pc()->GetTransceivers()[0]->mid(), initial_mid);
2128 }
2129
TEST_F(PeerConnectionJsepTest,RollbackToNegotiatedStableState)2130 TEST_F(PeerConnectionJsepTest, RollbackToNegotiatedStableState) {
2131 RTCConfiguration config;
2132 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
2133 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
2134 auto caller = CreatePeerConnection(config);
2135 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
2136 auto callee = CreatePeerConnection(config);
2137 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2138 EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal());
2139 caller->AddVideoTrack("a");
2140 callee->AddVideoTrack("b");
2141 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2142 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 2u);
2143 auto audio_transport =
2144 callee->pc()->GetTransceivers()[0]->sender()->dtls_transport();
2145 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
2146 callee->pc()->GetTransceivers()[1]->sender()->dtls_transport());
2147 EXPECT_NE(callee->pc()->GetTransceivers()[1]->sender()->dtls_transport(),
2148 nullptr);
2149 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
2150 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
2151 audio_transport); // Audio must remain working after rollback.
2152 EXPECT_EQ(callee->pc()->GetTransceivers()[1]->sender()->dtls_transport(),
2153 nullptr);
2154 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2155
2156 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
2157 audio_transport); // Audio transport is still the same.
2158 }
2159
TEST_F(PeerConnectionJsepTest,RollbackHasToDestroyTransport)2160 TEST_F(PeerConnectionJsepTest, RollbackHasToDestroyTransport) {
2161 RTCConfiguration config;
2162 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
2163 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
2164 auto pc = CreatePeerConnection(config);
2165 pc->AddAudioTrack("a");
2166 pc->AddVideoTrack("b");
2167 EXPECT_TRUE(pc->CreateOfferAndSetAsLocal());
2168 auto offer = pc->CreateOffer();
2169 EXPECT_EQ(pc->pc()->GetTransceivers().size(), 2u);
2170 auto audio_transport =
2171 pc->pc()->GetTransceivers()[0]->sender()->dtls_transport();
2172 EXPECT_EQ(pc->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
2173 pc->pc()->GetTransceivers()[1]->sender()->dtls_transport());
2174 EXPECT_NE(pc->pc()->GetTransceivers()[1]->sender()->dtls_transport(),
2175 nullptr);
2176 EXPECT_TRUE(pc->SetRemoteDescription(pc->CreateRollback()));
2177 EXPECT_TRUE(pc->SetLocalDescription(std::move(offer)));
2178 EXPECT_NE(pc->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
2179 nullptr);
2180 EXPECT_NE(pc->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
2181 audio_transport);
2182 }
2183
TEST_F(PeerConnectionJsepTest,RollbackLocalDirectionChange)2184 TEST_F(PeerConnectionJsepTest, RollbackLocalDirectionChange) {
2185 auto caller = CreatePeerConnection();
2186 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
2187 auto callee = CreatePeerConnection();
2188 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2189 EXPECT_TRUE(
2190 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
2191 callee->AddAudioTrack("a");
2192 callee->pc()->GetTransceivers()[0]->SetDirectionWithError(
2193 RtpTransceiverDirection::kSendOnly);
2194 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2195 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
2196 auto audio_transport =
2197 callee->pc()->GetTransceivers()[0]->receiver()->dtls_transport();
2198 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
2199 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->direction(),
2200 RtpTransceiverDirection::kSendOnly);
2201 // One way audio must remain working after rollback as local direction change
2202 // comes in effect after completing full negotiation round.
2203 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->receiver()->dtls_transport(),
2204 audio_transport);
2205 }
2206
TEST_F(PeerConnectionJsepTest,RollbackRemoteDirectionChange)2207 TEST_F(PeerConnectionJsepTest, RollbackRemoteDirectionChange) {
2208 auto caller = CreatePeerConnection();
2209 auto caller_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
2210 auto callee = CreatePeerConnection();
2211 callee->AddAudioTrack("a");
2212 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2213 EXPECT_TRUE(
2214 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
2215 // In stable make remote audio receive only.
2216 caller_transceiver->SetDirectionWithError(RtpTransceiverDirection::kRecvOnly);
2217 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2218 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
2219 // The direction attribute is not modified by the offer.
2220 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->direction(),
2221 RtpTransceiverDirection::kSendRecv);
2222 auto audio_transport =
2223 callee->pc()->GetTransceivers()[0]->sender()->dtls_transport();
2224 EXPECT_EQ(callee->observer()->add_track_events_.size(), 1u);
2225 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 1u);
2226 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
2227 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
2228 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->direction(),
2229 RtpTransceiverDirection::kSendRecv);
2230 // One way audio must remain working after rollback.
2231 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
2232 audio_transport);
2233 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 1u);
2234 }
2235
TEST_F(PeerConnectionJsepTest,RollbackRestoresFiredDirectionAndOnTrackCanFireAgain)2236 TEST_F(PeerConnectionJsepTest,
2237 RollbackRestoresFiredDirectionAndOnTrackCanFireAgain) {
2238 auto caller = CreatePeerConnection();
2239 auto caller_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
2240 auto callee = CreatePeerConnection();
2241 callee->AddAudioTrack("a");
2242 ASSERT_EQ(callee->pc()->GetTransceivers().size(), 1u);
2243 auto callee_transceiver = callee->pc()->GetTransceivers()[0];
2244 EXPECT_FALSE(callee_transceiver->fired_direction().has_value());
2245 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2246 EXPECT_TRUE(callee_transceiver->fired_direction().has_value());
2247 EXPECT_EQ(callee->observer()->add_track_events_.size(), 1u);
2248 // The existing transceiver becomes associated. Because it already exists,
2249 // rolling it back does not remove the transceiver, so if ontrack fires again
2250 // later it will be because the transceiver's internal states were restored
2251 // rather than due to the creation of a new transceiver.
2252 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
2253
2254 // Rollback: the transceiver is no longer receiving.
2255 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
2256 EXPECT_FALSE(callee_transceiver->fired_direction().has_value());
2257 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
2258
2259 // Set the remote offer again: ontrack should fire on the same transceiver.
2260 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2261 EXPECT_TRUE(callee_transceiver->fired_direction().has_value());
2262 EXPECT_EQ(callee->observer()->add_track_events_.size(), 2u);
2263 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
2264 }
2265
TEST_F(PeerConnectionJsepTest,RollbackFromInactiveToReceivingMakesOnTrackFire)2266 TEST_F(PeerConnectionJsepTest,
2267 RollbackFromInactiveToReceivingMakesOnTrackFire) {
2268 auto caller = CreatePeerConnection();
2269 auto caller_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
2270 auto callee = CreatePeerConnection();
2271 // Perform full O/A so that transceiver is associated. Ontrack fires.
2272 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2273 EXPECT_EQ(callee->observer()->add_track_events_.size(), 1u);
2274 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 0u);
2275 ASSERT_TRUE(
2276 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
2277
2278 // Start negotiating to make the transceiver inactive. Onremovetrack fires.
2279 caller_transceiver->SetDirectionWithError(RtpTransceiverDirection::kInactive);
2280 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2281 EXPECT_EQ(callee->observer()->add_track_events_.size(), 1u);
2282 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 1u);
2283
2284 // Rollback the inactivation. Ontrack should fire again.
2285 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
2286 EXPECT_EQ(callee->observer()->add_track_events_.size(), 2u);
2287 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 1u);
2288 }
2289
TEST_F(PeerConnectionJsepTest,RollbackAfterMultipleSLD)2290 TEST_F(PeerConnectionJsepTest, RollbackAfterMultipleSLD) {
2291 auto callee = CreatePeerConnection();
2292 callee->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
2293 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2294 callee->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2295 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2296 callee->observer()->clear_legacy_renegotiation_needed();
2297 callee->observer()->clear_latest_negotiation_needed_event();
2298 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
2299 EXPECT_TRUE(callee->observer()->legacy_renegotiation_needed());
2300 EXPECT_TRUE(callee->observer()->has_negotiation_needed_event());
2301 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 2u);
2302 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), absl::nullopt);
2303 EXPECT_EQ(callee->pc()->GetTransceivers()[1]->mid(), absl::nullopt);
2304 }
2305
TEST_F(PeerConnectionJsepTest,NoRollbackNeeded)2306 TEST_F(PeerConnectionJsepTest, NoRollbackNeeded) {
2307 auto caller = CreatePeerConnection();
2308 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
2309 auto callee = CreatePeerConnection();
2310 callee->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
2311 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
2312 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
2313 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2314 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2315 }
2316
TEST_F(PeerConnectionJsepTest,RollbackMultipleStreamChanges)2317 TEST_F(PeerConnectionJsepTest, RollbackMultipleStreamChanges) {
2318 auto callee = CreatePeerConnection();
2319 auto caller = CreatePeerConnection();
2320 caller->AddAudioTrack("a_1", {"id_1"});
2321 caller->AddVideoTrack("v_0", {"id_0"}); // Provide an extra stream id.
2322 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2323 EXPECT_TRUE(
2324 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
2325 caller->pc()->GetTransceivers()[0]->sender()->SetStreams({"id_2"});
2326 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2327 caller->pc()->GetTransceivers()[0]->sender()->SetStreams({"id_3"});
2328 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2329 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->receiver()->stream_ids()[0],
2330 "id_3");
2331 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
2332 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->receiver()->stream_ids().size(),
2333 1u);
2334 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->receiver()->stream_ids()[0],
2335 "id_1");
2336 }
2337
TEST_F(PeerConnectionJsepTest,DataChannelImplicitRollback)2338 TEST_F(PeerConnectionJsepTest, DataChannelImplicitRollback) {
2339 RTCConfiguration config;
2340 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
2341 config.enable_implicit_rollback = true;
2342 auto caller = CreatePeerConnection(config);
2343 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2344 auto callee = CreatePeerConnection(config);
2345 callee->CreateDataChannel("dummy");
2346 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2347 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2348 EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal());
2349 EXPECT_TRUE(callee->observer()->legacy_renegotiation_needed());
2350 EXPECT_TRUE(callee->observer()->has_negotiation_needed_event());
2351 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2352 }
2353
TEST_F(PeerConnectionJsepTest,RollbackRemoteDataChannelThenAddTransceiver)2354 TEST_F(PeerConnectionJsepTest, RollbackRemoteDataChannelThenAddTransceiver) {
2355 auto caller = CreatePeerConnection();
2356 auto callee = CreatePeerConnection();
2357 caller->CreateDataChannel("dummy");
2358 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2359 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
2360 callee->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2361 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2362 }
2363
TEST_F(PeerConnectionJsepTest,RollbackRemoteDataChannelThenAddTransceiverAndDataChannel)2364 TEST_F(PeerConnectionJsepTest,
2365 RollbackRemoteDataChannelThenAddTransceiverAndDataChannel) {
2366 auto caller = CreatePeerConnection();
2367 auto callee = CreatePeerConnection();
2368 caller->CreateDataChannel("dummy");
2369 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2370 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
2371 callee->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2372 callee->CreateDataChannel("dummy");
2373 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2374 }
2375
TEST_F(PeerConnectionJsepTest,RollbackRemoteDataChannelThenAddDataChannel)2376 TEST_F(PeerConnectionJsepTest, RollbackRemoteDataChannelThenAddDataChannel) {
2377 auto caller = CreatePeerConnection();
2378 auto callee = CreatePeerConnection();
2379 caller->CreateDataChannel("dummy");
2380 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2381 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
2382 callee->CreateDataChannel("dummy");
2383 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2384 }
2385
TEST_F(PeerConnectionJsepTest,RollbackRemoteTransceiverThenAddDataChannel)2386 TEST_F(PeerConnectionJsepTest, RollbackRemoteTransceiverThenAddDataChannel) {
2387 auto caller = CreatePeerConnection();
2388 auto callee = CreatePeerConnection();
2389 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2390 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2391 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
2392 callee->CreateDataChannel("dummy");
2393 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2394 }
2395
TEST_F(PeerConnectionJsepTest,RollbackRemoteTransceiverThenAddDataChannelAndTransceiver)2396 TEST_F(PeerConnectionJsepTest,
2397 RollbackRemoteTransceiverThenAddDataChannelAndTransceiver) {
2398 auto caller = CreatePeerConnection();
2399 auto callee = CreatePeerConnection();
2400 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2401 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2402 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
2403 callee->CreateDataChannel("dummy");
2404 callee->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2405 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2406 }
2407
2408 } // namespace webrtc
2409