blob: 4d9884d6150e01a1844e07202668cd66559fb8e8 [file] [log] [blame]
Steve Antondcc3c022017-12-22 16:02:54 -08001/*
2 * Copyright 2017 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Mirko Bonadei317a1f02019-09-17 17:06:18 +020011#include <memory>
12
Danil Chapovalov9da25bd2019-06-20 10:19:42 +020013#include "api/task_queue/default_task_queue_factory.h"
Steve Anton10542f22019-01-11 09:11:00 -080014#include "media/engine/webrtc_media_engine.h"
Danil Chapovalov9da25bd2019-06-20 10:19:42 +020015#include "media/engine/webrtc_media_engine_defaults.h"
Steve Anton10542f22019-01-11 09:11:00 -080016#include "pc/media_session.h"
17#include "pc/peer_connection_factory.h"
18#include "pc/peer_connection_wrapper.h"
19#include "pc/sdp_utils.h"
Steve Antondcc3c022017-12-22 16:02:54 -080020#ifdef WEBRTC_ANDROID
Steve Anton10542f22019-01-11 09:11:00 -080021#include "pc/test/android_test_initializer.h"
Steve Antondcc3c022017-12-22 16:02:54 -080022#endif
Steve Anton10542f22019-01-11 09:11:00 -080023#include "pc/test/fake_audio_capture_module.h"
Steve Antondcc3c022017-12-22 16:02:54 -080024#include "rtc_base/gunit.h"
Steve Anton10542f22019-01-11 09:11:00 -080025#include "rtc_base/virtual_socket_server.h"
Steve Antondcc3c022017-12-22 16:02:54 -080026#include "test/gmock.h"
Per Kjellander2bca0082020-08-28 09:15:15 +020027#include "test/pc/sctp/fake_sctp_transport.h"
Steve Antondcc3c022017-12-22 16:02:54 -080028
29// This file contains tests that ensure the PeerConnection's implementation of
30// CreateOffer/CreateAnswer/SetLocalDescription/SetRemoteDescription conform
31// to the JavaScript Session Establishment Protocol (JSEP).
32// For now these semantics are only available when configuring the
33// PeerConnection with Unified Plan, but eventually that will be the default.
34
35namespace webrtc {
36
37using cricket::MediaContentDescription;
38using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
Steve Antondcc3c022017-12-22 16:02:54 -080039using ::testing::Combine;
40using ::testing::ElementsAre;
Steve Antonef65ef12018-01-10 17:15:20 -080041using ::testing::UnorderedElementsAre;
Jonas Olssona4d87372019-07-05 19:08:33 +020042using ::testing::Values;
Steve Antondcc3c022017-12-22 16:02:54 -080043
Per Kjellander2bca0082020-08-28 09:15:15 +020044PeerConnectionFactoryDependencies CreatePeerConnectionFactoryDependencies() {
45 PeerConnectionFactoryDependencies dependencies;
46 dependencies.worker_thread = rtc::Thread::Current();
47 dependencies.network_thread = rtc::Thread::Current();
48 dependencies.signaling_thread = rtc::Thread::Current();
49 dependencies.task_queue_factory = CreateDefaultTaskQueueFactory();
50 cricket::MediaEngineDependencies media_deps;
51 media_deps.task_queue_factory = dependencies.task_queue_factory.get();
52 media_deps.adm = FakeAudioCaptureModule::Create();
53 SetMediaEngineDefaults(&media_deps);
54 dependencies.media_engine = cricket::CreateMediaEngine(std::move(media_deps));
55 dependencies.call_factory = CreateCallFactory();
56 dependencies.sctp_factory = std::make_unique<FakeSctpTransportFactory>();
57 return dependencies;
58}
Steve Antonfa2260d2017-12-28 16:38:23 -080059
Steve Antondcc3c022017-12-22 16:02:54 -080060class PeerConnectionJsepTest : public ::testing::Test {
61 protected:
62 typedef std::unique_ptr<PeerConnectionWrapper> WrapperPtr;
63
64 PeerConnectionJsepTest()
65 : vss_(new rtc::VirtualSocketServer()), main_(vss_.get()) {
66#ifdef WEBRTC_ANDROID
67 InitializeAndroidObjects();
68#endif
Steve Antondcc3c022017-12-22 16:02:54 -080069 }
70
71 WrapperPtr CreatePeerConnection() {
72 RTCConfiguration config;
73 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
74 return CreatePeerConnection(config);
75 }
76
77 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
Per Kjellander2bca0082020-08-28 09:15:15 +020078 rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory =
79 CreateModularPeerConnectionFactory(
80 CreatePeerConnectionFactoryDependencies());
Mirko Bonadei317a1f02019-09-17 17:06:18 +020081 auto observer = std::make_unique<MockPeerConnectionObserver>();
Steve Antonfa2260d2017-12-28 16:38:23 -080082 auto pc = pc_factory->CreatePeerConnection(config, nullptr, nullptr,
83 observer.get());
Steve Antondcc3c022017-12-22 16:02:54 -080084 if (!pc) {
85 return nullptr;
86 }
87
Yves Gerey4e933292018-10-31 15:36:05 +010088 observer->SetPeerConnectionInterface(pc.get());
Mirko Bonadei317a1f02019-09-17 17:06:18 +020089 return std::make_unique<PeerConnectionWrapper>(pc_factory, pc,
90 std::move(observer));
Steve Antondcc3c022017-12-22 16:02:54 -080091 }
92
93 std::unique_ptr<rtc::VirtualSocketServer> vss_;
94 rtc::AutoSocketServerThread main_;
Steve Antondcc3c022017-12-22 16:02:54 -080095};
96
97// Tests for JSEP initial offer generation.
98
99// Test that an offer created by a PeerConnection with no transceivers generates
100// no media sections.
101TEST_F(PeerConnectionJsepTest, EmptyInitialOffer) {
102 auto caller = CreatePeerConnection();
Steve Antonfa2260d2017-12-28 16:38:23 -0800103
Steve Antondcc3c022017-12-22 16:02:54 -0800104 auto offer = caller->CreateOffer();
Steve Antonfa2260d2017-12-28 16:38:23 -0800105 ASSERT_EQ(0u, offer->description()->contents().size());
Steve Antondcc3c022017-12-22 16:02:54 -0800106}
107
108// Test that an initial offer with one audio track generates one audio media
109// section.
110TEST_F(PeerConnectionJsepTest, AudioOnlyInitialOffer) {
111 auto caller = CreatePeerConnection();
112 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
Steve Antondcc3c022017-12-22 16:02:54 -0800113
Steve Antonfa2260d2017-12-28 16:38:23 -0800114 auto offer = caller->CreateOffer();
Steve Antondcc3c022017-12-22 16:02:54 -0800115 auto contents = offer->description()->contents();
116 ASSERT_EQ(1u, contents.size());
117 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, contents[0].media_description()->type());
118}
119
120// Test than an initial offer with one video track generates one video media
121// section
122TEST_F(PeerConnectionJsepTest, VideoOnlyInitialOffer) {
123 auto caller = CreatePeerConnection();
124 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
Steve Antondcc3c022017-12-22 16:02:54 -0800125
Steve Antonfa2260d2017-12-28 16:38:23 -0800126 auto offer = caller->CreateOffer();
Steve Antondcc3c022017-12-22 16:02:54 -0800127 auto contents = offer->description()->contents();
128 ASSERT_EQ(1u, contents.size());
129 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, contents[0].media_description()->type());
130}
131
Steve Antonfa2260d2017-12-28 16:38:23 -0800132// Test that an initial offer with one data channel generates one data media
133// section.
134TEST_F(PeerConnectionJsepTest, DataOnlyInitialOffer) {
135 auto caller = CreatePeerConnection();
136 caller->CreateDataChannel("dc");
137
138 auto offer = caller->CreateOffer();
139 auto contents = offer->description()->contents();
140 ASSERT_EQ(1u, contents.size());
141 EXPECT_EQ(cricket::MEDIA_TYPE_DATA, contents[0].media_description()->type());
142}
143
144// Test that creating multiple data channels only results in one data section
145// generated in the offer.
146TEST_F(PeerConnectionJsepTest, MultipleDataChannelsCreateOnlyOneDataSection) {
147 auto caller = CreatePeerConnection();
148 caller->CreateDataChannel("first");
149 caller->CreateDataChannel("second");
150 caller->CreateDataChannel("third");
151
152 auto offer = caller->CreateOffer();
153 ASSERT_EQ(1u, offer->description()->contents().size());
154}
155
Steve Antondcc3c022017-12-22 16:02:54 -0800156// Test that multiple media sections in the initial offer are ordered in the
157// order the transceivers were added to the PeerConnection. This is required by
158// JSEP section 5.2.1.
159TEST_F(PeerConnectionJsepTest, MediaSectionsInInitialOfferOrderedCorrectly) {
160 auto caller = CreatePeerConnection();
161 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
162 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
163 RtpTransceiverInit init;
164 init.direction = RtpTransceiverDirection::kSendOnly;
165 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init);
Steve Antondcc3c022017-12-22 16:02:54 -0800166
Steve Antonfa2260d2017-12-28 16:38:23 -0800167 auto offer = caller->CreateOffer();
Steve Antondcc3c022017-12-22 16:02:54 -0800168 auto contents = offer->description()->contents();
169 ASSERT_EQ(3u, contents.size());
170
171 const MediaContentDescription* media_description1 =
172 contents[0].media_description();
173 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, media_description1->type());
174 EXPECT_EQ(RtpTransceiverDirection::kSendRecv,
175 media_description1->direction());
176
177 const MediaContentDescription* media_description2 =
178 contents[1].media_description();
179 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, media_description2->type());
180 EXPECT_EQ(RtpTransceiverDirection::kSendRecv,
181 media_description2->direction());
182
183 const MediaContentDescription* media_description3 =
184 contents[2].media_description();
185 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, media_description3->type());
186 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
187 media_description3->direction());
188}
189
190// Test that media sections in the initial offer have different mids.
191TEST_F(PeerConnectionJsepTest, MediaSectionsInInitialOfferHaveDifferentMids) {
192 auto caller = CreatePeerConnection();
193 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
194 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
Steve Antonfa2260d2017-12-28 16:38:23 -0800195
Steve Antondcc3c022017-12-22 16:02:54 -0800196 auto offer = caller->CreateOffer();
Steve Antondcc3c022017-12-22 16:02:54 -0800197 auto contents = offer->description()->contents();
198 ASSERT_EQ(2u, contents.size());
199 EXPECT_NE(contents[0].name, contents[1].name);
200}
201
202TEST_F(PeerConnectionJsepTest,
203 StoppedTransceiverHasNoMediaSectionInInitialOffer) {
204 auto caller = CreatePeerConnection();
205 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
Harald Alvestrand6060df52020-08-11 09:54:02 +0200206 transceiver->StopInternal();
Steve Antondcc3c022017-12-22 16:02:54 -0800207
208 auto offer = caller->CreateOffer();
209 EXPECT_EQ(0u, offer->description()->contents().size());
210}
211
212// Tests for JSEP SetLocalDescription with a local offer.
213
214TEST_F(PeerConnectionJsepTest, SetLocalEmptyOfferCreatesNoTransceivers) {
215 auto caller = CreatePeerConnection();
Steve Antonfa2260d2017-12-28 16:38:23 -0800216
Steve Antondcc3c022017-12-22 16:02:54 -0800217 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
218
219 EXPECT_THAT(caller->pc()->GetTransceivers(), ElementsAre());
220 EXPECT_THAT(caller->pc()->GetSenders(), ElementsAre());
221 EXPECT_THAT(caller->pc()->GetReceivers(), ElementsAre());
222}
223
224TEST_F(PeerConnectionJsepTest, SetLocalOfferSetsTransceiverMid) {
225 auto caller = CreatePeerConnection();
226 auto audio_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
227 auto video_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
228
229 auto offer = caller->CreateOffer();
230 std::string audio_mid = offer->description()->contents()[0].name;
231 std::string video_mid = offer->description()->contents()[1].name;
232
233 ASSERT_TRUE(caller->SetLocalDescription(std::move(offer)));
234
235 EXPECT_EQ(audio_mid, audio_transceiver->mid());
236 EXPECT_EQ(video_mid, video_transceiver->mid());
237}
238
239// Tests for JSEP SetRemoteDescription with a remote offer.
240
241// Test that setting a remote offer with sendrecv audio and video creates two
242// transceivers, one for receiving audio and one for receiving video.
243TEST_F(PeerConnectionJsepTest, SetRemoteOfferCreatesTransceivers) {
244 auto caller = CreatePeerConnection();
245 auto caller_audio = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
246 auto caller_video = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
247 auto callee = CreatePeerConnection();
248
249 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
250
251 auto transceivers = callee->pc()->GetTransceivers();
252 ASSERT_EQ(2u, transceivers.size());
Steve Anton1bc97162018-06-25 14:04:01 -0700253
Steve Anton69470252018-02-09 11:43:08 -0800254 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, transceivers[0]->media_type());
Steve Antondcc3c022017-12-22 16:02:54 -0800255 EXPECT_EQ(caller_audio->mid(), transceivers[0]->mid());
256 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly, transceivers[0]->direction());
Steve Anton1bc97162018-06-25 14:04:01 -0700257 EXPECT_EQ(0u, transceivers[0]->sender()->stream_ids().size());
258
Steve Anton69470252018-02-09 11:43:08 -0800259 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, transceivers[1]->media_type());
Steve Antondcc3c022017-12-22 16:02:54 -0800260 EXPECT_EQ(caller_video->mid(), transceivers[1]->mid());
261 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly, transceivers[1]->direction());
Steve Anton1bc97162018-06-25 14:04:01 -0700262 EXPECT_EQ(0u, transceivers[1]->sender()->stream_ids().size());
Steve Antondcc3c022017-12-22 16:02:54 -0800263}
264
265// Test that setting a remote offer with an audio track will reuse the
266// transceiver created for a local audio track added by AddTrack.
267// This is specified in JSEP section 5.10 (Applying a Remote Description). The
268// intent is to preserve backwards compatibility with clients who only use the
269// AddTrack API.
270TEST_F(PeerConnectionJsepTest, SetRemoteOfferReusesTransceiverFromAddTrack) {
271 auto caller = CreatePeerConnection();
272 caller->AddAudioTrack("a");
273 auto caller_audio = caller->pc()->GetTransceivers()[0];
274 auto callee = CreatePeerConnection();
275 callee->AddAudioTrack("a");
276
277 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
278
279 auto transceivers = callee->pc()->GetTransceivers();
280 ASSERT_EQ(1u, transceivers.size());
281 EXPECT_EQ(MediaStreamTrackInterface::kAudioKind,
282 transceivers[0]->receiver()->track()->kind());
283 EXPECT_EQ(caller_audio->mid(), transceivers[0]->mid());
284}
285
286// Test that setting a remote offer with an audio track marked sendonly will not
287// reuse a transceiver created by AddTrack. JSEP only allows the transceiver to
288// be reused if the offer direction is sendrecv or recvonly.
289TEST_F(PeerConnectionJsepTest,
290 SetRemoteOfferDoesNotReuseTransceiverIfDirectionSendOnly) {
291 auto caller = CreatePeerConnection();
292 caller->AddAudioTrack("a");
293 auto caller_audio = caller->pc()->GetTransceivers()[0];
Harald Alvestrand6060df52020-08-11 09:54:02 +0200294 caller_audio->SetDirectionWithError(RtpTransceiverDirection::kSendOnly);
Steve Antondcc3c022017-12-22 16:02:54 -0800295 auto callee = CreatePeerConnection();
296 callee->AddAudioTrack("a");
297
298 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
299
300 auto transceivers = callee->pc()->GetTransceivers();
301 ASSERT_EQ(2u, transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200302 EXPECT_EQ(absl::nullopt, transceivers[0]->mid());
Steve Antondcc3c022017-12-22 16:02:54 -0800303 EXPECT_EQ(caller_audio->mid(), transceivers[1]->mid());
304}
305
306// Test that setting a remote offer with an audio track will not reuse a
307// transceiver added by AddTransceiver. The logic for reusing a transceiver is
308// specific to those added by AddTrack and is tested above.
309TEST_F(PeerConnectionJsepTest,
310 SetRemoteOfferDoesNotReuseTransceiverFromAddTransceiver) {
311 auto caller = CreatePeerConnection();
312 caller->AddAudioTrack("a");
313 auto callee = CreatePeerConnection();
314 auto transceiver = callee->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
315
316 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
317
318 auto transceivers = callee->pc()->GetTransceivers();
319 ASSERT_EQ(2u, transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200320 EXPECT_EQ(absl::nullopt, transceivers[0]->mid());
Steve Antondcc3c022017-12-22 16:02:54 -0800321 EXPECT_EQ(caller->pc()->GetTransceivers()[0]->mid(), transceivers[1]->mid());
322 EXPECT_EQ(MediaStreamTrackInterface::kAudioKind,
323 transceivers[1]->receiver()->track()->kind());
324}
325
326// Test that setting a remote offer with an audio track will not reuse a
327// transceiver created for a local video track added by AddTrack.
328TEST_F(PeerConnectionJsepTest,
329 SetRemoteOfferDoesNotReuseTransceiverOfWrongType) {
330 auto caller = CreatePeerConnection();
331 caller->AddAudioTrack("a");
332 auto callee = CreatePeerConnection();
333 auto video_sender = callee->AddVideoTrack("v");
334
335 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
336
337 auto transceivers = callee->pc()->GetTransceivers();
338 ASSERT_EQ(2u, transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200339 EXPECT_EQ(absl::nullopt, transceivers[0]->mid());
Steve Antondcc3c022017-12-22 16:02:54 -0800340 EXPECT_EQ(caller->pc()->GetTransceivers()[0]->mid(), transceivers[1]->mid());
341 EXPECT_EQ(MediaStreamTrackInterface::kAudioKind,
342 transceivers[1]->receiver()->track()->kind());
343}
344
345// Test that setting a remote offer with an audio track will not reuse a
346// stopped transceiver.
347TEST_F(PeerConnectionJsepTest, SetRemoteOfferDoesNotReuseStoppedTransceiver) {
348 auto caller = CreatePeerConnection();
349 caller->AddAudioTrack("a");
350 auto callee = CreatePeerConnection();
351 callee->AddAudioTrack("a");
Harald Alvestrand6060df52020-08-11 09:54:02 +0200352 callee->pc()->GetTransceivers()[0]->StopInternal();
Steve Antondcc3c022017-12-22 16:02:54 -0800353
354 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
355
356 auto transceivers = callee->pc()->GetTransceivers();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200357 ASSERT_EQ(1u, transceivers.size());
358 EXPECT_EQ(caller->pc()->GetTransceivers()[0]->mid(), transceivers[0]->mid());
359 EXPECT_FALSE(transceivers[0]->stopped());
Steve Antondcc3c022017-12-22 16:02:54 -0800360}
361
362// Test that audio and video transceivers created on the remote side with
363// AddTrack will all be reused if there is the same number of audio/video tracks
364// in the remote offer. Additionally, this tests that transceivers are
365// successfully matched even if they are in a different order on the remote
366// side.
367TEST_F(PeerConnectionJsepTest, SetRemoteOfferReusesTransceiversOfBothTypes) {
368 auto caller = CreatePeerConnection();
369 caller->AddVideoTrack("v");
370 caller->AddAudioTrack("a");
371 auto callee = CreatePeerConnection();
372 callee->AddAudioTrack("a");
373 callee->AddVideoTrack("v");
374
375 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
376
377 auto caller_transceivers = caller->pc()->GetTransceivers();
378 auto callee_transceivers = callee->pc()->GetTransceivers();
379 ASSERT_EQ(2u, callee_transceivers.size());
380 EXPECT_EQ(caller_transceivers[0]->mid(), callee_transceivers[1]->mid());
381 EXPECT_EQ(caller_transceivers[1]->mid(), callee_transceivers[0]->mid());
382}
383
384// Tests for JSEP initial CreateAnswer.
385
386// Test that the answer to a remote offer creates media sections for each
387// offered media in the same order and with the same mids.
388TEST_F(PeerConnectionJsepTest, CreateAnswerHasSameMidsAsOffer) {
389 auto caller = CreatePeerConnection();
390 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
391 auto second_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
392 auto third_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
Steve Antonfa2260d2017-12-28 16:38:23 -0800393 caller->CreateDataChannel("dc");
Steve Antondcc3c022017-12-22 16:02:54 -0800394 auto callee = CreatePeerConnection();
395
Steve Antonfa2260d2017-12-28 16:38:23 -0800396 auto offer = caller->CreateOffer();
397 const auto* offer_data = cricket::GetFirstDataContent(offer->description());
398 ASSERT_TRUE(
399 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
400 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
Steve Antondcc3c022017-12-22 16:02:54 -0800401
402 auto answer = callee->CreateAnswer();
403 auto contents = answer->description()->contents();
Steve Antonfa2260d2017-12-28 16:38:23 -0800404 ASSERT_EQ(4u, contents.size());
Steve Antondcc3c022017-12-22 16:02:54 -0800405 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, contents[0].media_description()->type());
Steve Antonfa2260d2017-12-28 16:38:23 -0800406 EXPECT_EQ(first_transceiver->mid(), contents[0].name);
Steve Antondcc3c022017-12-22 16:02:54 -0800407 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, contents[1].media_description()->type());
Steve Antonfa2260d2017-12-28 16:38:23 -0800408 EXPECT_EQ(second_transceiver->mid(), contents[1].name);
Steve Antondcc3c022017-12-22 16:02:54 -0800409 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, contents[2].media_description()->type());
Steve Antonfa2260d2017-12-28 16:38:23 -0800410 EXPECT_EQ(third_transceiver->mid(), contents[2].name);
411 EXPECT_EQ(cricket::MEDIA_TYPE_DATA, contents[3].media_description()->type());
412 EXPECT_EQ(offer_data->name, contents[3].name);
Steve Antondcc3c022017-12-22 16:02:54 -0800413}
414
415// Test that an answering media section is marked as rejected if the underlying
416// transceiver has been stopped.
417TEST_F(PeerConnectionJsepTest, CreateAnswerRejectsStoppedTransceiver) {
418 auto caller = CreatePeerConnection();
419 caller->AddAudioTrack("a");
420 auto callee = CreatePeerConnection();
421
422 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
423
Harald Alvestrand6060df52020-08-11 09:54:02 +0200424 callee->pc()->GetTransceivers()[0]->StopInternal();
Steve Antondcc3c022017-12-22 16:02:54 -0800425
426 auto answer = callee->CreateAnswer();
427 auto contents = answer->description()->contents();
428 ASSERT_EQ(1u, contents.size());
429 EXPECT_TRUE(contents[0].rejected);
430}
431
432// Test that CreateAnswer will generate media sections which will only send or
433// receive if the offer indicates it can do the reciprocating direction.
434// The full matrix is tested more extensively in MediaSession.
435TEST_F(PeerConnectionJsepTest, CreateAnswerNegotiatesDirection) {
436 auto caller = CreatePeerConnection();
437 RtpTransceiverInit init;
438 init.direction = RtpTransceiverDirection::kSendOnly;
439 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init);
440 auto callee = CreatePeerConnection();
441 callee->AddAudioTrack("a");
442
443 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
444
445 auto answer = callee->CreateAnswer();
446 auto contents = answer->description()->contents();
447 ASSERT_EQ(1u, contents.size());
448 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
449 contents[0].media_description()->direction());
450}
451
452// Tests for JSEP SetLocalDescription with a local answer.
453// Note that these test only the additional behaviors not covered by
454// SetLocalDescription with a local offer.
455
456// Test that SetLocalDescription with an answer sets the current_direction
457// property of the transceivers mentioned in the session description.
458TEST_F(PeerConnectionJsepTest, SetLocalAnswerUpdatesCurrentDirection) {
459 auto caller = CreatePeerConnection();
460 auto caller_audio = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
Harald Alvestrand6060df52020-08-11 09:54:02 +0200461 caller_audio->SetDirectionWithError(RtpTransceiverDirection::kRecvOnly);
Steve Antondcc3c022017-12-22 16:02:54 -0800462 auto callee = CreatePeerConnection();
463 callee->AddAudioTrack("a");
464
465 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
466 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
467
468 auto transceivers = callee->pc()->GetTransceivers();
469 ASSERT_EQ(1u, transceivers.size());
470 // Since the offer was recvonly and the transceiver direction is sendrecv,
471 // the negotiated direction will be sendonly.
472 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
473 transceivers[0]->current_direction());
474}
475
476// Tests for JSEP SetRemoteDescription with a remote answer.
477// Note that these test only the additional behaviors not covered by
478// SetRemoteDescription with a remote offer.
479
480TEST_F(PeerConnectionJsepTest, SetRemoteAnswerUpdatesCurrentDirection) {
481 auto caller = CreatePeerConnection();
482 caller->AddAudioTrack("a");
483 auto callee = CreatePeerConnection();
484 callee->AddAudioTrack("a");
485 auto callee_audio = callee->pc()->GetTransceivers()[0];
Harald Alvestrand6060df52020-08-11 09:54:02 +0200486 callee_audio->SetDirectionWithError(RtpTransceiverDirection::kSendOnly);
Steve Antondcc3c022017-12-22 16:02:54 -0800487
488 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
489 ASSERT_TRUE(
490 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
491
492 auto transceivers = caller->pc()->GetTransceivers();
493 ASSERT_EQ(1u, transceivers.size());
494 // Since the remote transceiver was set to sendonly, the negotiated direction
495 // in the answer would be sendonly which we apply as recvonly to the local
496 // transceiver.
497 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
498 transceivers[0]->current_direction());
499}
500
501// Tests for multiple round trips.
502
503// Test that setting a transceiver with the inactive direction does not stop it
504// on either the caller or the callee.
505TEST_F(PeerConnectionJsepTest, SettingTransceiverInactiveDoesNotStopIt) {
506 auto caller = CreatePeerConnection();
507 caller->AddAudioTrack("a");
508 auto callee = CreatePeerConnection();
509 callee->AddAudioTrack("a");
Harald Alvestrand6060df52020-08-11 09:54:02 +0200510 callee->pc()->GetTransceivers()[0]->SetDirectionWithError(
Steve Antondcc3c022017-12-22 16:02:54 -0800511 RtpTransceiverDirection::kInactive);
512
513 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
514 ASSERT_TRUE(
515 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
516
517 EXPECT_FALSE(caller->pc()->GetTransceivers()[0]->stopped());
518 EXPECT_FALSE(callee->pc()->GetTransceivers()[0]->stopped());
519}
520
521// Test that if a transceiver had been associated and later stopped, then a
522// media section is still generated for it and the media section is marked as
523// rejected.
524TEST_F(PeerConnectionJsepTest,
525 ReOfferMediaSectionForAssociatedStoppedTransceiverIsRejected) {
526 auto caller = CreatePeerConnection();
527 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
528 auto callee = CreatePeerConnection();
529
530 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
531 ASSERT_TRUE(
532 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
533
534 ASSERT_TRUE(transceiver->mid());
Harald Alvestrand6060df52020-08-11 09:54:02 +0200535 transceiver->StopInternal();
Steve Antondcc3c022017-12-22 16:02:54 -0800536
537 auto reoffer = caller->CreateOffer();
538 auto contents = reoffer->description()->contents();
539 ASSERT_EQ(1u, contents.size());
540 EXPECT_TRUE(contents[0].rejected);
541}
542
543// Test that stopping an associated transceiver on the caller side will stop the
544// corresponding transceiver on the remote side when the remote offer is
545// applied.
546TEST_F(PeerConnectionJsepTest,
547 StoppingTransceiverInOfferStopsTransceiverOnRemoteSide) {
548 auto caller = CreatePeerConnection();
549 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
550 auto callee = CreatePeerConnection();
551
552 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
553 ASSERT_TRUE(
554 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
555
Harald Alvestrand6060df52020-08-11 09:54:02 +0200556 transceiver->StopInternal();
Steve Antondcc3c022017-12-22 16:02:54 -0800557
558 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
559
560 auto transceivers = callee->pc()->GetTransceivers();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200561 EXPECT_EQ(0u, transceivers.size());
Steve Antondcc3c022017-12-22 16:02:54 -0800562}
563
564// Test that CreateOffer will only generate a recycled media section if the
565// transceiver to be recycled has been seen stopped by the other side first.
566TEST_F(PeerConnectionJsepTest,
567 CreateOfferDoesNotRecycleMediaSectionIfFirstStopped) {
568 auto caller = CreatePeerConnection();
569 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
570 auto callee = CreatePeerConnection();
571
572 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
573 ASSERT_TRUE(
574 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
575
576 auto second_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
Harald Alvestrand6060df52020-08-11 09:54:02 +0200577 first_transceiver->StopInternal();
Steve Antondcc3c022017-12-22 16:02:54 -0800578
579 auto reoffer = caller->CreateOffer();
580 auto contents = reoffer->description()->contents();
581 ASSERT_EQ(2u, contents.size());
582 EXPECT_TRUE(contents[0].rejected);
583 EXPECT_FALSE(contents[1].rejected);
584}
585
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800586// Test that the offer/answer and the transceivers are correctly generated and
587// updated when the media section is recycled after the callee stops a
588// transceiver and sends an answer with a 0 port.
589TEST_F(PeerConnectionJsepTest,
590 RecycleMediaSectionWhenStoppingTransceiverOnAnswerer) {
591 auto caller = CreatePeerConnection();
592 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
593 auto callee = CreatePeerConnection();
594
595 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
Harald Alvestrand6060df52020-08-11 09:54:02 +0200596 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
597 callee->pc()->GetTransceivers()[0]->StopInternal();
598 ASSERT_EQ(0u, callee->pc()->GetTransceivers().size());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800599 ASSERT_TRUE(
600 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
601 EXPECT_TRUE(first_transceiver->stopped());
Harald Alvestrand6060df52020-08-11 09:54:02 +0200602 // First transceivers aren't dissociated yet on caller side.
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200603 ASSERT_NE(absl::nullopt, first_transceiver->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800604 std::string first_mid = *first_transceiver->mid();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200605 // They are disassociated on callee side.
606 ASSERT_EQ(0u, callee->pc()->GetTransceivers().size());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800607
608 // New offer exchange with new transceivers that recycles the m section
609 // correctly.
610 caller->AddAudioTrack("audio2");
611 callee->AddAudioTrack("audio2");
612 auto offer = caller->CreateOffer();
613 auto offer_contents = offer->description()->contents();
614 std::string second_mid = offer_contents[0].name;
615 ASSERT_EQ(1u, offer_contents.size());
616 EXPECT_FALSE(offer_contents[0].rejected);
617 EXPECT_NE(first_mid, second_mid);
618
619 // Setting the offer on each side will dissociate the first transceivers and
620 // associate the new transceivers.
621 ASSERT_TRUE(
622 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200623 EXPECT_EQ(absl::nullopt, first_transceiver->mid());
Harald Alvestrand6060df52020-08-11 09:54:02 +0200624 ASSERT_EQ(1u, caller->pc()->GetTransceivers().size());
625 EXPECT_EQ(second_mid, caller->pc()->GetTransceivers()[0]->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800626 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
Harald Alvestrand6060df52020-08-11 09:54:02 +0200627 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
628 EXPECT_EQ(second_mid, callee->pc()->GetTransceivers()[0]->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800629
630 // The new answer should also recycle the m section correctly.
631 auto answer = callee->CreateAnswer();
632 auto answer_contents = answer->description()->contents();
633 ASSERT_EQ(1u, answer_contents.size());
634 EXPECT_FALSE(answer_contents[0].rejected);
635 EXPECT_EQ(second_mid, answer_contents[0].name);
636
637 // Finishing the negotiation shouldn't add or dissociate any transceivers.
638 ASSERT_TRUE(
639 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
640 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
641 auto caller_transceivers = caller->pc()->GetTransceivers();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200642 ASSERT_EQ(1u, caller_transceivers.size());
643 EXPECT_EQ(second_mid, caller_transceivers[0]->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800644 auto callee_transceivers = callee->pc()->GetTransceivers();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200645 ASSERT_EQ(1u, callee_transceivers.size());
646 EXPECT_EQ(second_mid, callee_transceivers[0]->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800647}
648
649// Test that creating/setting a local offer that recycles an m= section is
650// idempotent.
651TEST_F(PeerConnectionJsepTest, CreateOfferRecyclesWhenOfferingTwice) {
652 // Do a negotiation with a port 0 for the media section.
653 auto caller = CreatePeerConnection();
654 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
655 auto callee = CreatePeerConnection();
656 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Harald Alvestrand6060df52020-08-11 09:54:02 +0200657 first_transceiver->StopInternal();
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800658 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
659 caller->AddAudioTrack("audio2");
660
661 // Create a new offer that recycles the media section and set it as a local
662 // description.
663 auto offer = caller->CreateOffer();
664 auto offer_contents = offer->description()->contents();
665 ASSERT_EQ(1u, offer_contents.size());
666 EXPECT_FALSE(offer_contents[0].rejected);
667 ASSERT_TRUE(caller->SetLocalDescription(std::move(offer)));
Harald Alvestrand6060df52020-08-11 09:54:02 +0200668 ASSERT_EQ(1u, caller->pc()->GetTransceivers().size());
669 EXPECT_FALSE(caller->pc()->GetTransceivers()[0]->stopped());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800670 std::string second_mid = offer_contents[0].name;
671
672 // Create another new offer and set the local description again without the
673 // rest of any negotation ocurring.
674 auto second_offer = caller->CreateOffer();
675 auto second_offer_contents = second_offer->description()->contents();
676 ASSERT_EQ(1u, second_offer_contents.size());
677 EXPECT_FALSE(second_offer_contents[0].rejected);
678 // The mid shouldn't change.
679 EXPECT_EQ(second_mid, second_offer_contents[0].name);
680
681 ASSERT_TRUE(caller->SetLocalDescription(std::move(second_offer)));
682 // Make sure that the caller's transceivers are associated correctly.
683 auto caller_transceivers = caller->pc()->GetTransceivers();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200684 ASSERT_EQ(1u, caller_transceivers.size());
685 EXPECT_EQ(second_mid, caller_transceivers[0]->mid());
686 EXPECT_FALSE(caller_transceivers[0]->stopped());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800687}
688
Steve Antondcc3c022017-12-22 16:02:54 -0800689// Test that the offer/answer and transceivers for both the caller and callee
690// side are generated/updated correctly when recycling an audio/video media
691// section as a media section of either the same or opposite type.
Steve Anton5c72e712018-12-10 14:25:30 -0800692// Correct recycling works as follows:
693// - The m= section is re-offered with a new MID value and the new media type.
694// - The previously-associated transceiver is dissociated when the new offer is
695// set as a local description on the offerer or as a remote description on
696// the answerer.
697// - The new transceiver is associated with the new MID value.
Steve Antondcc3c022017-12-22 16:02:54 -0800698class RecycleMediaSectionTest
699 : public PeerConnectionJsepTest,
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200700 public ::testing::WithParamInterface<
Steve Antondcc3c022017-12-22 16:02:54 -0800701 std::tuple<cricket::MediaType, cricket::MediaType>> {
702 protected:
703 RecycleMediaSectionTest() {
704 first_type_ = std::get<0>(GetParam());
705 second_type_ = std::get<1>(GetParam());
706 }
707
708 cricket::MediaType first_type_;
709 cricket::MediaType second_type_;
710};
711
Steve Anton5c72e712018-12-10 14:25:30 -0800712// Test that recycling works properly when a new transceiver recycles an m=
713// section that was rejected in both the current local and remote descriptions.
714TEST_P(RecycleMediaSectionTest, CurrentLocalAndCurrentRemoteRejected) {
Steve Antondcc3c022017-12-22 16:02:54 -0800715 auto caller = CreatePeerConnection();
716 auto first_transceiver = caller->AddTransceiver(first_type_);
717 auto callee = CreatePeerConnection();
718
719 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
720
721 std::string first_mid = *first_transceiver->mid();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200722 first_transceiver->StopInternal();
Steve Antondcc3c022017-12-22 16:02:54 -0800723
724 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
725
726 auto second_transceiver = caller->AddTransceiver(second_type_);
727
728 // The offer should reuse the previous media section but allocate a new MID
729 // and change the media type.
730 auto offer = caller->CreateOffer();
731 auto offer_contents = offer->description()->contents();
732 ASSERT_EQ(1u, offer_contents.size());
733 EXPECT_FALSE(offer_contents[0].rejected);
734 EXPECT_EQ(second_type_, offer_contents[0].media_description()->type());
735 std::string second_mid = offer_contents[0].name;
736 EXPECT_NE(first_mid, second_mid);
737
738 // Setting the local offer will dissociate the previous transceiver and set
739 // the MID for the new transceiver.
740 ASSERT_TRUE(
741 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200742 EXPECT_EQ(absl::nullopt, first_transceiver->mid());
Steve Antondcc3c022017-12-22 16:02:54 -0800743 EXPECT_EQ(second_mid, second_transceiver->mid());
744
745 // Setting the remote offer will dissociate the previous transceiver and
746 // create a new transceiver for the media section.
747 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
748 auto callee_transceivers = callee->pc()->GetTransceivers();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200749 ASSERT_EQ(1u, callee_transceivers.size());
750 EXPECT_EQ(second_mid, callee_transceivers[0]->mid());
751 EXPECT_EQ(second_type_, callee_transceivers[0]->media_type());
Steve Antondcc3c022017-12-22 16:02:54 -0800752
753 // The answer should have only one media section for the new transceiver.
754 auto answer = callee->CreateAnswer();
755 auto answer_contents = answer->description()->contents();
756 ASSERT_EQ(1u, answer_contents.size());
757 EXPECT_FALSE(answer_contents[0].rejected);
758 EXPECT_EQ(second_mid, answer_contents[0].name);
759 EXPECT_EQ(second_type_, answer_contents[0].media_description()->type());
760
761 // Setting the local answer should succeed.
762 ASSERT_TRUE(
763 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
764
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800765 // Setting the remote answer should succeed and not create any new
766 // transceivers.
Steve Antondcc3c022017-12-22 16:02:54 -0800767 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
Harald Alvestrand6060df52020-08-11 09:54:02 +0200768 ASSERT_EQ(1u, caller->pc()->GetTransceivers().size());
769 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
Steve Antondcc3c022017-12-22 16:02:54 -0800770}
771
Steve Anton5c72e712018-12-10 14:25:30 -0800772// Test that recycling works properly when a new transceiver recycles an m=
773// section that was rejected in only the current remote description.
774TEST_P(RecycleMediaSectionTest, CurrentRemoteOnlyRejected) {
775 auto caller = CreatePeerConnection();
776 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
777 auto callee = CreatePeerConnection();
778
779 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
780
781 std::string first_mid = *caller_first_transceiver->mid();
782 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
783 auto callee_first_transceiver = callee->pc()->GetTransceivers()[0];
Harald Alvestrand6060df52020-08-11 09:54:02 +0200784 callee_first_transceiver->StopInternal();
Steve Anton5c72e712018-12-10 14:25:30 -0800785
786 // The answer will have a rejected m= section.
787 ASSERT_TRUE(
788 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
789
790 // The offer should reuse the previous media section but allocate a new MID
791 // and change the media type.
792 auto caller_second_transceiver = caller->AddTransceiver(second_type_);
793 auto offer = caller->CreateOffer();
794 const auto& offer_contents = offer->description()->contents();
795 ASSERT_EQ(1u, offer_contents.size());
796 EXPECT_FALSE(offer_contents[0].rejected);
797 EXPECT_EQ(second_type_, offer_contents[0].media_description()->type());
798 std::string second_mid = offer_contents[0].name;
799 EXPECT_NE(first_mid, second_mid);
800
801 // Setting the local offer will dissociate the previous transceiver and set
802 // the MID for the new transceiver.
803 ASSERT_TRUE(
804 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
805 EXPECT_EQ(absl::nullopt, caller_first_transceiver->mid());
806 EXPECT_EQ(second_mid, caller_second_transceiver->mid());
807
808 // Setting the remote offer will dissociate the previous transceiver and
809 // create a new transceiver for the media section.
810 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
811 auto callee_transceivers = callee->pc()->GetTransceivers();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200812 ASSERT_EQ(1u, callee_transceivers.size());
813 EXPECT_EQ(second_mid, callee_transceivers[0]->mid());
814 EXPECT_EQ(second_type_, callee_transceivers[0]->media_type());
Steve Anton5c72e712018-12-10 14:25:30 -0800815
816 // The answer should have only one media section for the new transceiver.
817 auto answer = callee->CreateAnswer();
818 auto answer_contents = answer->description()->contents();
819 ASSERT_EQ(1u, answer_contents.size());
820 EXPECT_FALSE(answer_contents[0].rejected);
821 EXPECT_EQ(second_mid, answer_contents[0].name);
822 EXPECT_EQ(second_type_, answer_contents[0].media_description()->type());
823
824 // Setting the local answer should succeed.
825 ASSERT_TRUE(
826 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
827
828 // Setting the remote answer should succeed and not create any new
829 // transceivers.
830 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
Harald Alvestrand6060df52020-08-11 09:54:02 +0200831 ASSERT_EQ(1u, caller->pc()->GetTransceivers().size());
832 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
Steve Anton5c72e712018-12-10 14:25:30 -0800833}
834
835// Test that recycling works properly when a new transceiver recycles an m=
836// section that was rejected only in the current local description.
837TEST_P(RecycleMediaSectionTest, CurrentLocalOnlyRejected) {
838 auto caller = CreatePeerConnection();
839 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
840 auto callee = CreatePeerConnection();
841
842 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
843
844 std::string first_mid = *caller_first_transceiver->mid();
845 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
846 auto callee_first_transceiver = callee->pc()->GetTransceivers()[0];
Harald Alvestrand6060df52020-08-11 09:54:02 +0200847 callee_first_transceiver->StopInternal();
Steve Anton5c72e712018-12-10 14:25:30 -0800848
849 // The answer will have a rejected m= section.
850 ASSERT_TRUE(
851 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
852
853 // The offer should reuse the previous media section but allocate a new MID
854 // and change the media type.
855 auto callee_second_transceiver = callee->AddTransceiver(second_type_);
856 auto offer = callee->CreateOffer();
857 const auto& offer_contents = offer->description()->contents();
858 ASSERT_EQ(1u, offer_contents.size());
859 EXPECT_FALSE(offer_contents[0].rejected);
860 EXPECT_EQ(second_type_, offer_contents[0].media_description()->type());
861 std::string second_mid = offer_contents[0].name;
862 EXPECT_NE(first_mid, second_mid);
863
864 // Setting the local offer will dissociate the previous transceiver and set
865 // the MID for the new transceiver.
866 ASSERT_TRUE(
867 callee->SetLocalDescription(CloneSessionDescription(offer.get())));
868 EXPECT_EQ(absl::nullopt, callee_first_transceiver->mid());
869 EXPECT_EQ(second_mid, callee_second_transceiver->mid());
870
871 // Setting the remote offer will dissociate the previous transceiver and
872 // create a new transceiver for the media section.
873 ASSERT_TRUE(caller->SetRemoteDescription(std::move(offer)));
874 auto caller_transceivers = caller->pc()->GetTransceivers();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200875 ASSERT_EQ(1u, caller_transceivers.size());
876 EXPECT_EQ(second_mid, caller_transceivers[0]->mid());
877 EXPECT_EQ(second_type_, caller_transceivers[0]->media_type());
Steve Anton5c72e712018-12-10 14:25:30 -0800878
879 // The answer should have only one media section for the new transceiver.
880 auto answer = caller->CreateAnswer();
881 auto answer_contents = answer->description()->contents();
882 ASSERT_EQ(1u, answer_contents.size());
883 EXPECT_FALSE(answer_contents[0].rejected);
884 EXPECT_EQ(second_mid, answer_contents[0].name);
885 EXPECT_EQ(second_type_, answer_contents[0].media_description()->type());
886
887 // Setting the local answer should succeed.
888 ASSERT_TRUE(
889 caller->SetLocalDescription(CloneSessionDescription(answer.get())));
890
891 // Setting the remote answer should succeed and not create any new
892 // transceivers.
893 ASSERT_TRUE(callee->SetRemoteDescription(std::move(answer)));
Harald Alvestrand6060df52020-08-11 09:54:02 +0200894 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
895 ASSERT_EQ(1u, caller->pc()->GetTransceivers().size());
Steve Anton5c72e712018-12-10 14:25:30 -0800896}
897
898// Test that a m= section is *not* recycled if the media section is only
899// rejected in the pending local description and there is no current remote
900// description.
901TEST_P(RecycleMediaSectionTest, PendingLocalRejectedAndNoRemote) {
902 auto caller = CreatePeerConnection();
903 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
904
905 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
906
907 std::string first_mid = *caller_first_transceiver->mid();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200908 caller_first_transceiver->StopInternal();
Steve Anton5c72e712018-12-10 14:25:30 -0800909
910 // The reoffer will have a rejected m= section.
911 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
912
913 auto caller_second_transceiver = caller->AddTransceiver(second_type_);
914
915 // The reoffer should not recycle the existing m= section since it is not
916 // rejected in either the *current* local or *current* remote description.
917 auto reoffer = caller->CreateOffer();
918 auto reoffer_contents = reoffer->description()->contents();
919 ASSERT_EQ(2u, reoffer_contents.size());
920 EXPECT_TRUE(reoffer_contents[0].rejected);
921 EXPECT_EQ(first_type_, reoffer_contents[0].media_description()->type());
922 EXPECT_EQ(first_mid, reoffer_contents[0].name);
923 EXPECT_FALSE(reoffer_contents[1].rejected);
924 EXPECT_EQ(second_type_, reoffer_contents[1].media_description()->type());
925 std::string second_mid = reoffer_contents[1].name;
926 EXPECT_NE(first_mid, second_mid);
927
928 ASSERT_TRUE(caller->SetLocalDescription(std::move(reoffer)));
929
930 // Both RtpTransceivers are associated.
931 EXPECT_EQ(first_mid, caller_first_transceiver->mid());
932 EXPECT_EQ(second_mid, caller_second_transceiver->mid());
933}
934
935// Test that a m= section is *not* recycled if the media section is only
936// rejected in the pending local description and not rejected in the current
937// remote description.
938TEST_P(RecycleMediaSectionTest, PendingLocalRejectedAndNotRejectedRemote) {
939 auto caller = CreatePeerConnection();
940 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
941 auto callee = CreatePeerConnection();
942
943 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
944
945 std::string first_mid = *caller_first_transceiver->mid();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200946 caller_first_transceiver->StopInternal();
Steve Anton5c72e712018-12-10 14:25:30 -0800947
948 // The reoffer will have a rejected m= section.
949 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
950
951 auto caller_second_transceiver = caller->AddTransceiver(second_type_);
952
953 // The reoffer should not recycle the existing m= section since it is not
954 // rejected in either the *current* local or *current* remote description.
955 auto reoffer = caller->CreateOffer();
956 auto reoffer_contents = reoffer->description()->contents();
957 ASSERT_EQ(2u, reoffer_contents.size());
958 EXPECT_TRUE(reoffer_contents[0].rejected);
959 EXPECT_EQ(first_type_, reoffer_contents[0].media_description()->type());
960 EXPECT_EQ(first_mid, reoffer_contents[0].name);
961 EXPECT_FALSE(reoffer_contents[1].rejected);
962 EXPECT_EQ(second_type_, reoffer_contents[1].media_description()->type());
963 std::string second_mid = reoffer_contents[1].name;
964 EXPECT_NE(first_mid, second_mid);
965
966 ASSERT_TRUE(caller->SetLocalDescription(std::move(reoffer)));
967
968 // Both RtpTransceivers are associated.
969 EXPECT_EQ(first_mid, caller_first_transceiver->mid());
970 EXPECT_EQ(second_mid, caller_second_transceiver->mid());
971}
972
973// Test that an m= section is *not* recycled if the media section is only
974// rejected in the pending remote description and there is no current local
975// description.
976TEST_P(RecycleMediaSectionTest, PendingRemoteRejectedAndNoLocal) {
977 auto caller = CreatePeerConnection();
978 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
979 auto callee = CreatePeerConnection();
980
981 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
982
983 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
984 auto callee_first_transceiver = callee->pc()->GetTransceivers()[0];
985 std::string first_mid = *callee_first_transceiver->mid();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200986 caller_first_transceiver->StopInternal();
Steve Anton5c72e712018-12-10 14:25:30 -0800987
988 // The reoffer will have a rejected m= section.
989 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
990
991 auto callee_second_transceiver = callee->AddTransceiver(second_type_);
992
993 // The reoffer should not recycle the existing m= section since it is not
994 // rejected in either the *current* local or *current* remote description.
995 auto reoffer = callee->CreateOffer();
996 auto reoffer_contents = reoffer->description()->contents();
997 ASSERT_EQ(2u, reoffer_contents.size());
998 EXPECT_TRUE(reoffer_contents[0].rejected);
999 EXPECT_EQ(first_type_, reoffer_contents[0].media_description()->type());
1000 EXPECT_EQ(first_mid, reoffer_contents[0].name);
1001 EXPECT_FALSE(reoffer_contents[1].rejected);
1002 EXPECT_EQ(second_type_, reoffer_contents[1].media_description()->type());
1003 std::string second_mid = reoffer_contents[1].name;
1004 EXPECT_NE(first_mid, second_mid);
1005
1006 // Note: Cannot actually set the reoffer since the callee is in the signaling
1007 // state 'have-remote-offer'.
1008}
1009
1010// Test that an m= section is *not* recycled if the media section is only
1011// rejected in the pending remote description and not rejected in the current
1012// local description.
1013TEST_P(RecycleMediaSectionTest, PendingRemoteRejectedAndNotRejectedLocal) {
1014 auto caller = CreatePeerConnection();
1015 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
1016 auto callee = CreatePeerConnection();
1017
1018 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1019
1020 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
1021 auto callee_first_transceiver = callee->pc()->GetTransceivers()[0];
1022 std::string first_mid = *callee_first_transceiver->mid();
Harald Alvestrand6060df52020-08-11 09:54:02 +02001023 caller_first_transceiver->StopInternal();
Steve Anton5c72e712018-12-10 14:25:30 -08001024
1025 // The reoffer will have a rejected m= section.
1026 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1027
1028 auto callee_second_transceiver = callee->AddTransceiver(second_type_);
1029
1030 // The reoffer should not recycle the existing m= section since it is not
1031 // rejected in either the *current* local or *current* remote description.
1032 auto reoffer = callee->CreateOffer();
1033 auto reoffer_contents = reoffer->description()->contents();
1034 ASSERT_EQ(2u, reoffer_contents.size());
1035 EXPECT_TRUE(reoffer_contents[0].rejected);
1036 EXPECT_EQ(first_type_, reoffer_contents[0].media_description()->type());
1037 EXPECT_EQ(first_mid, reoffer_contents[0].name);
1038 EXPECT_FALSE(reoffer_contents[1].rejected);
1039 EXPECT_EQ(second_type_, reoffer_contents[1].media_description()->type());
1040 std::string second_mid = reoffer_contents[1].name;
1041 EXPECT_NE(first_mid, second_mid);
1042
1043 // Note: Cannot actually set the reoffer since the callee is in the signaling
1044 // state 'have-remote-offer'.
1045}
1046
Steve Antondcc3c022017-12-22 16:02:54 -08001047// Test all combinations of audio and video as the first and second media type
1048// for the media section. This is needed for full test coverage because
1049// MediaSession has separate functions for processing audio and video media
1050// sections.
Mirko Bonadeic84f6612019-01-31 12:20:57 +01001051INSTANTIATE_TEST_SUITE_P(
Steve Antondcc3c022017-12-22 16:02:54 -08001052 PeerConnectionJsepTest,
1053 RecycleMediaSectionTest,
1054 Combine(Values(cricket::MEDIA_TYPE_AUDIO, cricket::MEDIA_TYPE_VIDEO),
1055 Values(cricket::MEDIA_TYPE_AUDIO, cricket::MEDIA_TYPE_VIDEO)));
1056
Steve Antonfa2260d2017-12-28 16:38:23 -08001057// Test that a new data channel section will not reuse a recycleable audio or
1058// video media section. Additionally, tests that the new section is added to the
1059// end of the session description.
1060TEST_F(PeerConnectionJsepTest, DataChannelDoesNotRecycleMediaSection) {
1061 auto caller = CreatePeerConnection();
1062 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1063 auto callee = CreatePeerConnection();
1064
1065 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1066
Harald Alvestrand6060df52020-08-11 09:54:02 +02001067 transceiver->StopInternal();
Steve Antonfa2260d2017-12-28 16:38:23 -08001068
1069 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1070
1071 caller->CreateDataChannel("dc");
1072
1073 auto offer = caller->CreateOffer();
1074 auto offer_contents = offer->description()->contents();
1075 ASSERT_EQ(2u, offer_contents.size());
1076 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO,
1077 offer_contents[0].media_description()->type());
1078 EXPECT_EQ(cricket::MEDIA_TYPE_DATA,
1079 offer_contents[1].media_description()->type());
1080
1081 ASSERT_TRUE(
1082 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
1083 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1084
1085 auto answer = callee->CreateAnswer();
1086 auto answer_contents = answer->description()->contents();
1087 ASSERT_EQ(2u, answer_contents.size());
1088 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO,
1089 answer_contents[0].media_description()->type());
1090 EXPECT_EQ(cricket::MEDIA_TYPE_DATA,
1091 answer_contents[1].media_description()->type());
1092}
1093
1094// Test that if a new track is added to an existing session that has a data,
1095// the new section comes at the end of the new offer, after the existing data
1096// section.
1097TEST_F(PeerConnectionJsepTest, AudioTrackAddedAfterDataSectionInReoffer) {
1098 auto caller = CreatePeerConnection();
1099 caller->CreateDataChannel("dc");
1100 auto callee = CreatePeerConnection();
1101
1102 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1103
1104 caller->AddAudioTrack("a");
1105
1106 auto offer = caller->CreateOffer();
1107 auto contents = offer->description()->contents();
1108 ASSERT_EQ(2u, contents.size());
1109 EXPECT_EQ(cricket::MEDIA_TYPE_DATA, contents[0].media_description()->type());
1110 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, contents[1].media_description()->type());
1111}
1112
Steve Antondcc3c022017-12-22 16:02:54 -08001113// Tests for MID properties.
1114
1115static void RenameSection(size_t mline_index,
1116 const std::string& new_mid,
1117 SessionDescriptionInterface* sdesc) {
1118 cricket::SessionDescription* desc = sdesc->description();
1119 std::string old_mid = desc->contents()[mline_index].name;
1120 desc->contents()[mline_index].name = new_mid;
1121 desc->transport_infos()[mline_index].content_name = new_mid;
1122 const cricket::ContentGroup* bundle =
1123 desc->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1124 if (bundle) {
1125 cricket::ContentGroup new_bundle = *bundle;
1126 if (new_bundle.RemoveContentName(old_mid)) {
1127 new_bundle.AddContentName(new_mid);
1128 }
1129 desc->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1130 desc->AddGroup(new_bundle);
1131 }
1132}
1133
1134// Test that two PeerConnections can have a successful offer/answer exchange if
1135// the MIDs are changed from the defaults.
1136TEST_F(PeerConnectionJsepTest, OfferAnswerWithChangedMids) {
1137 constexpr char kFirstMid[] = "nondefaultmid";
1138 constexpr char kSecondMid[] = "randommid";
1139
1140 auto caller = CreatePeerConnection();
1141 caller->AddAudioTrack("a");
1142 caller->AddAudioTrack("b");
1143 auto callee = CreatePeerConnection();
1144
1145 auto offer = caller->CreateOffer();
1146 RenameSection(0, kFirstMid, offer.get());
1147 RenameSection(1, kSecondMid, offer.get());
1148
1149 ASSERT_TRUE(
1150 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
1151 auto caller_transceivers = caller->pc()->GetTransceivers();
1152 EXPECT_EQ(kFirstMid, caller_transceivers[0]->mid());
1153 EXPECT_EQ(kSecondMid, caller_transceivers[1]->mid());
1154
1155 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1156 auto callee_transceivers = callee->pc()->GetTransceivers();
1157 EXPECT_EQ(kFirstMid, callee_transceivers[0]->mid());
1158 EXPECT_EQ(kSecondMid, callee_transceivers[1]->mid());
1159
1160 auto answer = callee->CreateAnswer();
1161 auto answer_contents = answer->description()->contents();
1162 EXPECT_EQ(kFirstMid, answer_contents[0].name);
1163 EXPECT_EQ(kSecondMid, answer_contents[1].name);
1164
1165 ASSERT_TRUE(
1166 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
1167 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
1168}
1169
1170// Test that CreateOffer will generate a MID that is not already used if the
1171// default it would have picked is already taken. This is tested by using a
1172// third PeerConnection to determine what the default would be for the second
1173// media section then setting that as the first media section's MID.
1174TEST_F(PeerConnectionJsepTest, CreateOfferGeneratesUniqueMidIfAlreadyTaken) {
1175 // First, find what the default MID is for the second media section.
1176 auto pc = CreatePeerConnection();
1177 pc->AddAudioTrack("a");
1178 pc->AddAudioTrack("b");
1179 auto default_offer = pc->CreateOffer();
1180 std::string default_second_mid =
1181 default_offer->description()->contents()[1].name;
1182
1183 // Now, do an offer/answer with one track which has the MID set to the default
1184 // second MID.
1185 auto caller = CreatePeerConnection();
1186 caller->AddAudioTrack("a");
1187 auto callee = CreatePeerConnection();
1188
1189 auto offer = caller->CreateOffer();
1190 RenameSection(0, default_second_mid, offer.get());
1191
1192 ASSERT_TRUE(
1193 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
1194 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1195 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1196
1197 // Add a second track and ensure that the MID is different.
1198 caller->AddAudioTrack("b");
1199
1200 auto reoffer = caller->CreateOffer();
1201 auto reoffer_contents = reoffer->description()->contents();
1202 EXPECT_EQ(default_second_mid, reoffer_contents[0].name);
1203 EXPECT_NE(reoffer_contents[0].name, reoffer_contents[1].name);
1204}
1205
Steve Antonfa2260d2017-12-28 16:38:23 -08001206// Test that if an audio or video section has the default data section MID, then
1207// CreateOffer will generate a unique MID for the newly added data section.
1208TEST_F(PeerConnectionJsepTest,
1209 CreateOfferGeneratesUniqueMidForDataSectionIfAlreadyTaken) {
1210 // First, find what the default MID is for the data channel.
1211 auto pc = CreatePeerConnection();
1212 pc->CreateDataChannel("dc");
1213 auto default_offer = pc->CreateOffer();
1214 std::string default_data_mid =
1215 default_offer->description()->contents()[0].name;
1216
1217 // Now do an offer/answer with one audio track which has a MID set to the
1218 // default data MID.
1219 auto caller = CreatePeerConnection();
1220 caller->AddAudioTrack("a");
1221 auto callee = CreatePeerConnection();
1222
1223 auto offer = caller->CreateOffer();
1224 RenameSection(0, default_data_mid, offer.get());
1225
1226 ASSERT_TRUE(
1227 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
1228 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1229 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1230
1231 // Add a data channel and ensure that the MID is different.
1232 caller->CreateDataChannel("dc");
1233
1234 auto reoffer = caller->CreateOffer();
1235 auto reoffer_contents = reoffer->description()->contents();
1236 EXPECT_EQ(default_data_mid, reoffer_contents[0].name);
1237 EXPECT_NE(reoffer_contents[0].name, reoffer_contents[1].name);
1238}
1239
Steve Antondcc3c022017-12-22 16:02:54 -08001240// Test that a reoffer initiated by the callee adds a new track to the caller.
1241TEST_F(PeerConnectionJsepTest, CalleeDoesReoffer) {
1242 auto caller = CreatePeerConnection();
1243 caller->AddAudioTrack("a");
1244 auto callee = CreatePeerConnection();
1245 callee->AddAudioTrack("a");
1246 callee->AddVideoTrack("v");
1247
1248 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1249
1250 EXPECT_EQ(1u, caller->pc()->GetTransceivers().size());
1251 EXPECT_EQ(2u, callee->pc()->GetTransceivers().size());
1252
1253 ASSERT_TRUE(callee->ExchangeOfferAnswerWith(caller.get()));
1254
1255 EXPECT_EQ(2u, caller->pc()->GetTransceivers().size());
1256 EXPECT_EQ(2u, callee->pc()->GetTransceivers().size());
1257}
1258
Steve Anton02ee47c2018-01-10 16:26:06 -08001259// Tests for MSID properties.
1260
1261// Test that adding a track with AddTrack results in an offer that signals the
1262// track's ID.
1263TEST_F(PeerConnectionJsepTest, AddingTrackWithAddTrackSpecifiesTrackId) {
1264 const std::string kTrackId = "audio_track";
1265
1266 auto caller = CreatePeerConnection();
1267 caller->AddAudioTrack(kTrackId);
1268
1269 auto offer = caller->CreateOffer();
1270 auto contents = offer->description()->contents();
1271 ASSERT_EQ(1u, contents.size());
1272 auto streams = contents[0].media_description()->streams();
1273 ASSERT_EQ(1u, streams.size());
1274 EXPECT_EQ(kTrackId, streams[0].id);
1275}
1276
1277// Test that adding a track by calling AddTransceiver then SetTrack results in
1278// an offer that does not signal the track's ID and signals a random ID.
1279TEST_F(PeerConnectionJsepTest,
1280 AddingTrackWithAddTransceiverSpecifiesRandomTrackId) {
1281 const std::string kTrackId = "audio_track";
1282
1283 auto caller = CreatePeerConnection();
1284 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1285 transceiver->sender()->SetTrack(caller->CreateAudioTrack(kTrackId));
1286
1287 auto offer = caller->CreateOffer();
1288 auto contents = offer->description()->contents();
1289 ASSERT_EQ(1u, contents.size());
1290 auto streams = contents[0].media_description()->streams();
1291 ASSERT_EQ(1u, streams.size());
1292 EXPECT_NE(kTrackId, streams[0].id);
1293}
1294
Steve Anton5f94aa22018-02-01 10:58:30 -08001295// Test that if the transceiver is recvonly or inactive, then no MSID
1296// information is included in the offer.
1297TEST_F(PeerConnectionJsepTest, NoMsidInOfferIfTransceiverDirectionHasNoSend) {
1298 auto caller = CreatePeerConnection();
1299
1300 RtpTransceiverInit init_recvonly;
1301 init_recvonly.direction = RtpTransceiverDirection::kRecvOnly;
1302 ASSERT_TRUE(caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init_recvonly));
1303
1304 RtpTransceiverInit init_inactive;
1305 init_inactive.direction = RtpTransceiverDirection::kInactive;
1306 ASSERT_TRUE(caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init_inactive));
1307
1308 auto offer = caller->CreateOffer();
1309 auto contents = offer->description()->contents();
1310 ASSERT_EQ(2u, contents.size());
1311 // MSID is specified in the first stream, so no streams means no MSID.
1312 EXPECT_EQ(0u, contents[0].media_description()->streams().size());
1313 EXPECT_EQ(0u, contents[1].media_description()->streams().size());
1314}
1315
1316// Test that if an answer negotiates transceiver directions of recvonly or
1317// inactive, then no MSID information is included in the answer.
1318TEST_F(PeerConnectionJsepTest, NoMsidInAnswerIfNoRespondingTracks) {
1319 auto caller = CreatePeerConnection();
1320 auto callee = CreatePeerConnection();
1321
1322 // recvonly transceiver will get negotiated to inactive since the callee has
1323 // no tracks to send in response.
1324 RtpTransceiverInit init_recvonly;
1325 init_recvonly.direction = RtpTransceiverDirection::kRecvOnly;
1326 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init_recvonly);
1327
1328 // sendrecv transceiver will get negotiated to recvonly since the callee has
1329 // no tracks to send in response.
1330 RtpTransceiverInit init_sendrecv;
1331 init_sendrecv.direction = RtpTransceiverDirection::kSendRecv;
1332 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init_sendrecv);
1333
1334 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1335
1336 auto answer = callee->CreateAnswer();
1337 auto contents = answer->description()->contents();
1338 ASSERT_EQ(2u, contents.size());
1339 // MSID is specified in the first stream, so no streams means no MSID.
1340 EXPECT_EQ(0u, contents[0].media_description()->streams().size());
1341 EXPECT_EQ(0u, contents[1].media_description()->streams().size());
1342}
1343
1344// Test that the MSID is included even if the transceiver direction has changed
1345// to inactive if the transceiver had previously sent media.
1346TEST_F(PeerConnectionJsepTest, IncludeMsidEvenIfDirectionHasChanged) {
1347 auto caller = CreatePeerConnection();
1348 caller->AddAudioTrack("audio");
1349 auto callee = CreatePeerConnection();
1350 callee->AddAudioTrack("audio");
1351
1352 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1353
Harald Alvestrand6060df52020-08-11 09:54:02 +02001354 caller->pc()->GetTransceivers()[0]->SetDirectionWithError(
Steve Anton5f94aa22018-02-01 10:58:30 -08001355 RtpTransceiverDirection::kInactive);
1356
1357 // The transceiver direction on both sides will turn to inactive.
1358 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1359
1360 auto* offer = callee->pc()->remote_description();
1361 auto offer_contents = offer->description()->contents();
1362 ASSERT_EQ(1u, offer_contents.size());
1363 // MSID is specified in the first stream. If it is present, assume that MSID
1364 // is there.
1365 EXPECT_EQ(1u, offer_contents[0].media_description()->streams().size());
1366
1367 auto* answer = caller->pc()->remote_description();
1368 auto answer_contents = answer->description()->contents();
1369 ASSERT_EQ(1u, answer_contents.size());
1370 EXPECT_EQ(1u, answer_contents[0].media_description()->streams().size());
1371}
1372
1373// Test that stopping a RtpTransceiver will cause future offers to not include
1374// any MSID information for that section.
1375TEST_F(PeerConnectionJsepTest, RemoveMsidIfTransceiverStopped) {
1376 auto caller = CreatePeerConnection();
1377 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1378 auto callee = CreatePeerConnection();
1379
1380 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1381
Harald Alvestrand6060df52020-08-11 09:54:02 +02001382 transceiver->StopInternal();
Steve Anton5f94aa22018-02-01 10:58:30 -08001383
1384 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1385
1386 auto* offer = callee->pc()->remote_description();
1387 auto offer_contents = offer->description()->contents();
1388 ASSERT_EQ(1u, offer_contents.size());
1389 // MSID is specified in the first stream, so no streams means no MSID.
1390 EXPECT_EQ(0u, offer_contents[0].media_description()->streams().size());
1391}
1392
Steve Anton02ee47c2018-01-10 16:26:06 -08001393// Test that the callee RtpReceiver created by a call to SetRemoteDescription
1394// has its ID set to the signaled track ID.
1395TEST_F(PeerConnectionJsepTest,
1396 RtpReceiverCreatedBySetRemoteDescriptionHasSignaledTrackId) {
1397 const std::string kTrackId = "audio_track";
1398
1399 auto caller = CreatePeerConnection();
1400 auto callee = CreatePeerConnection();
1401 caller->AddAudioTrack(kTrackId);
1402
1403 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1404
1405 ASSERT_EQ(1u, callee->pc()->GetReceivers().size());
1406 auto receiver = callee->pc()->GetReceivers()[0];
1407 EXPECT_EQ(kTrackId, receiver->id());
1408}
1409
1410// Test that if the callee RtpReceiver is reused by a call to
1411// SetRemoteDescription, its ID does not change.
1412TEST_F(PeerConnectionJsepTest,
1413 RtpReceiverCreatedBeforeSetRemoteDescriptionKeepsId) {
1414 const std::string kTrackId = "audio_track";
1415
1416 auto caller = CreatePeerConnection();
1417 auto callee = CreatePeerConnection();
1418 caller->AddAudioTrack(kTrackId);
1419 callee->AddAudioTrack("dummy_track");
1420
1421 ASSERT_EQ(1u, callee->pc()->GetReceivers().size());
1422 auto receiver = callee->pc()->GetReceivers()[0];
1423 std::string receiver_id = receiver->id();
1424
1425 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1426
1427 EXPECT_EQ(receiver_id, receiver->id());
1428}
1429
Steve Antonef65ef12018-01-10 17:15:20 -08001430// Test that setting a remote offer with one track that has no streams fires off
1431// the correct OnAddTrack event.
1432TEST_F(PeerConnectionJsepTest,
1433 SetRemoteOfferWithOneTrackNoStreamFiresOnAddTrack) {
1434 const std::string kTrackLabel = "audio_track";
1435
1436 auto caller = CreatePeerConnection();
1437 auto callee = CreatePeerConnection();
1438 ASSERT_TRUE(caller->AddAudioTrack(kTrackLabel));
1439
1440 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1441
Seth Hampson5b4f0752018-04-02 16:31:36 -07001442 const auto& track_events = callee->observer()->add_track_events_;
1443 ASSERT_EQ(1u, track_events.size());
1444 const auto& event = track_events[0];
1445 EXPECT_EQ(kTrackLabel, event.receiver->track()->id());
1446 EXPECT_EQ(0u, event.streams.size());
Steve Antonef65ef12018-01-10 17:15:20 -08001447}
1448
1449// Test that setting a remote offer with one track that has one stream fires off
1450// the correct OnAddTrack event.
1451TEST_F(PeerConnectionJsepTest,
1452 SetRemoteOfferWithOneTrackOneStreamFiresOnAddTrack) {
1453 const std::string kTrackLabel = "audio_track";
Seth Hampson845e8782018-03-02 11:34:10 -08001454 const std::string kStreamId = "audio_stream";
Steve Antonef65ef12018-01-10 17:15:20 -08001455
1456 auto caller = CreatePeerConnection();
1457 auto callee = CreatePeerConnection();
Seth Hampson845e8782018-03-02 11:34:10 -08001458 ASSERT_TRUE(caller->AddAudioTrack(kTrackLabel, {kStreamId}));
Steve Antonef65ef12018-01-10 17:15:20 -08001459
1460 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1461
1462 const auto& track_events = callee->observer()->add_track_events_;
1463 ASSERT_EQ(1u, track_events.size());
1464 const auto& event = track_events[0];
1465 ASSERT_EQ(1u, event.streams.size());
1466 auto stream = event.streams[0];
Seth Hampson13b8bad2018-03-13 16:05:28 -07001467 EXPECT_EQ(kStreamId, stream->id());
Steve Antonef65ef12018-01-10 17:15:20 -08001468 EXPECT_THAT(track_events[0].snapshotted_stream_tracks.at(stream),
1469 ElementsAre(event.receiver->track()));
1470 EXPECT_EQ(event.receiver->streams(), track_events[0].streams);
1471}
1472
1473// Test that setting a remote offer with two tracks that share the same stream
1474// fires off two OnAddTrack events, both with the same stream that has both
1475// tracks present at the time of firing. This is to ensure that track events are
1476// not fired until SetRemoteDescription has finished processing all the media
1477// sections.
1478TEST_F(PeerConnectionJsepTest,
1479 SetRemoteOfferWithTwoTracksSameStreamFiresOnAddTrack) {
1480 const std::string kTrack1Label = "audio_track1";
1481 const std::string kTrack2Label = "audio_track2";
Seth Hampson845e8782018-03-02 11:34:10 -08001482 const std::string kSharedStreamId = "stream";
Steve Antonef65ef12018-01-10 17:15:20 -08001483
1484 auto caller = CreatePeerConnection();
1485 auto callee = CreatePeerConnection();
Seth Hampson845e8782018-03-02 11:34:10 -08001486 ASSERT_TRUE(caller->AddAudioTrack(kTrack1Label, {kSharedStreamId}));
1487 ASSERT_TRUE(caller->AddAudioTrack(kTrack2Label, {kSharedStreamId}));
Steve Antonef65ef12018-01-10 17:15:20 -08001488
1489 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1490
1491 const auto& track_events = callee->observer()->add_track_events_;
1492 ASSERT_EQ(2u, track_events.size());
1493 const auto& event1 = track_events[0];
1494 const auto& event2 = track_events[1];
1495 ASSERT_EQ(1u, event1.streams.size());
1496 auto stream = event1.streams[0];
1497 ASSERT_THAT(event2.streams, ElementsAre(stream));
1498 auto track1 = event1.receiver->track();
1499 auto track2 = event2.receiver->track();
1500 EXPECT_THAT(event1.snapshotted_stream_tracks.at(stream),
1501 UnorderedElementsAre(track1, track2));
1502 EXPECT_THAT(event2.snapshotted_stream_tracks.at(stream),
1503 UnorderedElementsAre(track1, track2));
1504}
1505
Seth Hampson5b4f0752018-04-02 16:31:36 -07001506// Test that setting a remote offer with one track that has two streams fires
1507// off the correct OnAddTrack event.
1508TEST_F(PeerConnectionJsepTest,
1509 SetRemoteOfferWithOneTrackTwoStreamFiresOnAddTrack) {
1510 const std::string kTrackLabel = "audio_track";
1511 const std::string kStreamId1 = "audio_stream1";
1512 const std::string kStreamId2 = "audio_stream2";
1513
1514 auto caller = CreatePeerConnection();
1515 auto callee = CreatePeerConnection();
1516 ASSERT_TRUE(caller->AddAudioTrack(kTrackLabel, {kStreamId1, kStreamId2}));
1517
1518 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1519
1520 const auto& track_events = callee->observer()->add_track_events_;
1521 ASSERT_EQ(1u, track_events.size());
1522 const auto& event = track_events[0];
1523 ASSERT_EQ(2u, event.streams.size());
1524 EXPECT_EQ(kStreamId1, event.streams[0]->id());
1525 EXPECT_EQ(kStreamId2, event.streams[1]->id());
1526}
Steve Antonef65ef12018-01-10 17:15:20 -08001527
Steve Anton54b84072018-02-20 15:19:52 -08001528// Test that if an RtpTransceiver with a current_direction set is stopped, then
1529// current_direction is changed to null.
1530TEST_F(PeerConnectionJsepTest, CurrentDirectionResetWhenRtpTransceiverStopped) {
1531 auto caller = CreatePeerConnection();
1532 auto callee = CreatePeerConnection();
1533
1534 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1535
1536 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1537
1538 ASSERT_TRUE(transceiver->current_direction());
Harald Alvestrand6060df52020-08-11 09:54:02 +02001539 transceiver->StopInternal();
1540 EXPECT_EQ(transceiver->current_direction(),
1541 RtpTransceiverDirection::kStopped);
Steve Anton54b84072018-02-20 15:19:52 -08001542}
1543
Steve Antonba42e992018-04-09 14:10:01 -07001544// Test that you can't set an answer on a PeerConnection before setting the
1545// offer.
Harald Alvestrand5081c0c2018-03-09 15:18:03 +01001546TEST_F(PeerConnectionJsepTest, AnswerBeforeOfferFails) {
1547 auto caller = CreatePeerConnection();
1548 auto callee = CreatePeerConnection();
Harald Alvestrand5081c0c2018-03-09 15:18:03 +01001549 caller->AddAudioTrack("audio");
Steve Antonba42e992018-04-09 14:10:01 -07001550
1551 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1552
1553 RTCError error;
1554 ASSERT_FALSE(caller->SetRemoteDescription(callee->CreateAnswer(), &error));
1555 EXPECT_EQ(RTCErrorType::INVALID_STATE, error.type());
1556}
1557
1558// Test that a Unified Plan PeerConnection fails to set a Plan B offer if it has
1559// two video tracks.
1560TEST_F(PeerConnectionJsepTest, TwoVideoPlanBToUnifiedPlanFails) {
1561 RTCConfiguration config_planb;
1562 config_planb.sdp_semantics = SdpSemantics::kPlanB;
1563 auto caller = CreatePeerConnection(config_planb);
1564 auto callee = CreatePeerConnection();
1565 caller->AddVideoTrack("video1");
1566 caller->AddVideoTrack("video2");
1567
1568 RTCError error;
1569 ASSERT_FALSE(callee->SetRemoteDescription(caller->CreateOffer(), &error));
1570 EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, error.type());
1571}
1572
1573// Test that a Unified Plan PeerConnection fails to set a Plan B answer if it
1574// has two video tracks.
1575TEST_F(PeerConnectionJsepTest, OneVideoUnifiedPlanToTwoVideoPlanBFails) {
1576 auto caller = CreatePeerConnection();
1577 RTCConfiguration config_planb;
1578 config_planb.sdp_semantics = SdpSemantics::kPlanB;
1579 auto callee = CreatePeerConnection(config_planb);
1580 caller->AddVideoTrack("video");
1581 callee->AddVideoTrack("video1");
1582 callee->AddVideoTrack("video2");
1583
1584 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1585
1586 RTCError error;
1587 ASSERT_FALSE(caller->SetRemoteDescription(caller->CreateAnswer(), &error));
1588 EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, error.type());
Harald Alvestrand5081c0c2018-03-09 15:18:03 +01001589}
1590
Steve Anton06817cd2018-12-18 15:55:30 -08001591// Removes the RTP header extension associated with the given URI from the media
1592// description.
1593static void RemoveRtpHeaderExtensionByUri(
1594 MediaContentDescription* media_description,
1595 absl::string_view uri) {
1596 std::vector<RtpExtension> header_extensions =
1597 media_description->rtp_header_extensions();
1598 header_extensions.erase(std::remove_if(
1599 header_extensions.begin(), header_extensions.end(),
1600 [uri](const RtpExtension& extension) { return extension.uri == uri; }));
1601 media_description->set_rtp_header_extensions(header_extensions);
1602}
1603
1604// Transforms a session description to emulate a legacy endpoint which does not
1605// support a=mid, BUNDLE, and the MID header extension.
1606static void ClearMids(SessionDescriptionInterface* sdesc) {
1607 cricket::SessionDescription* desc = sdesc->description();
1608 desc->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1609 cricket::ContentInfo* audio_content = cricket::GetFirstAudioContent(desc);
1610 if (audio_content) {
1611 desc->GetTransportInfoByName(audio_content->name)->content_name = "";
1612 audio_content->name = "";
1613 RemoveRtpHeaderExtensionByUri(audio_content->media_description(),
1614 RtpExtension::kMidUri);
1615 }
1616 cricket::ContentInfo* video_content = cricket::GetFirstVideoContent(desc);
1617 if (video_content) {
1618 desc->GetTransportInfoByName(video_content->name)->content_name = "";
1619 video_content->name = "";
1620 RemoveRtpHeaderExtensionByUri(video_content->media_description(),
1621 RtpExtension::kMidUri);
1622 }
1623}
1624
1625// Test that negotiation works with legacy endpoints which do not support a=mid.
1626TEST_F(PeerConnectionJsepTest, LegacyNoMidAudioOnlyOffer) {
1627 auto caller = CreatePeerConnection();
1628 caller->AddAudioTrack("audio");
1629 auto callee = CreatePeerConnection();
1630 callee->AddAudioTrack("audio");
1631
1632 auto offer = caller->CreateOffer();
1633 ClearMids(offer.get());
1634
1635 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1636 EXPECT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1637}
1638TEST_F(PeerConnectionJsepTest, LegacyNoMidAudioVideoOffer) {
1639 auto caller = CreatePeerConnection();
1640 caller->AddAudioTrack("audio");
1641 caller->AddVideoTrack("video");
1642 auto callee = CreatePeerConnection();
1643 callee->AddAudioTrack("audio");
1644 callee->AddVideoTrack("video");
1645
1646 auto offer = caller->CreateOffer();
1647 ClearMids(offer.get());
1648
1649 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1650 EXPECT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1651}
1652TEST_F(PeerConnectionJsepTest, LegacyNoMidAudioOnlyAnswer) {
1653 auto caller = CreatePeerConnection();
1654 caller->AddAudioTrack("audio");
1655 auto callee = CreatePeerConnection();
1656 callee->AddAudioTrack("audio");
1657
1658 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1659
1660 auto answer = callee->CreateAnswer();
1661 ClearMids(answer.get());
1662
1663 EXPECT_TRUE(caller->SetRemoteDescription(std::move(answer)));
1664}
1665TEST_F(PeerConnectionJsepTest, LegacyNoMidAudioVideoAnswer) {
1666 auto caller = CreatePeerConnection();
1667 caller->AddAudioTrack("audio");
1668 caller->AddVideoTrack("video");
1669 auto callee = CreatePeerConnection();
1670 callee->AddAudioTrack("audio");
1671 callee->AddVideoTrack("video");
1672
1673 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1674
1675 auto answer = callee->CreateAnswer();
1676 ClearMids(answer.get());
1677
1678 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
1679}
1680
Steve Antond7180cc2019-02-07 10:44:53 -08001681// Test that negotiation works with legacy endpoints which do not support a=mid
1682// when setting two remote descriptions without setting a local description in
1683// between.
1684TEST_F(PeerConnectionJsepTest, LegacyNoMidTwoRemoteOffers) {
1685 auto caller = CreatePeerConnection();
1686 caller->AddAudioTrack("audio");
1687 auto callee = CreatePeerConnection();
1688 callee->AddAudioTrack("audio");
1689
1690 auto offer = caller->CreateOffer();
1691 ClearMids(offer.get());
1692
1693 ASSERT_TRUE(
1694 callee->SetRemoteDescription(CloneSessionDescription(offer.get())));
1695 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1696 EXPECT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1697}
1698
Steve Antonceac0152018-12-19 11:32:20 -08001699// Test that SetLocalDescription fails if a=mid lines are missing.
1700TEST_F(PeerConnectionJsepTest, SetLocalDescriptionFailsMissingMid) {
1701 auto caller = CreatePeerConnection();
1702 caller->AddAudioTrack("audio");
1703
1704 auto offer = caller->CreateOffer();
1705 ClearMids(offer.get());
1706
1707 std::string error;
1708 ASSERT_FALSE(caller->SetLocalDescription(std::move(offer), &error));
1709 EXPECT_EQ(
1710 "Failed to set local offer sdp: A media section is missing a MID "
1711 "attribute.",
1712 error);
1713}
1714
Eldar Rello5ab79e62019-10-09 18:29:44 +03001715TEST_F(PeerConnectionJsepTest, RollbackSupportedInUnifiedPlan) {
1716 RTCConfiguration config;
1717 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
1718 config.enable_implicit_rollback = true;
1719 auto caller = CreatePeerConnection(config);
1720 auto callee = CreatePeerConnection(config);
1721 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
1722 EXPECT_TRUE(caller->SetLocalDescription(caller->CreateRollback()));
1723 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
1724 EXPECT_TRUE(caller->SetRemoteDescription(caller->CreateRollback()));
1725 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
1726 EXPECT_TRUE(caller->SetRemoteDescription(callee->CreateOffer()));
1727}
1728
1729TEST_F(PeerConnectionJsepTest, RollbackNotSupportedInPlanB) {
1730 RTCConfiguration config;
1731 config.sdp_semantics = SdpSemantics::kPlanB;
1732 config.enable_implicit_rollback = true;
1733 auto caller = CreatePeerConnection(config);
1734 auto callee = CreatePeerConnection(config);
1735 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
1736 EXPECT_FALSE(caller->SetLocalDescription(caller->CreateRollback()));
1737 EXPECT_FALSE(caller->SetRemoteDescription(caller->CreateRollback()));
1738 EXPECT_FALSE(caller->SetRemoteDescription(callee->CreateOffer()));
1739}
1740
1741TEST_F(PeerConnectionJsepTest, RollbackFailsInStableState) {
1742 auto caller = CreatePeerConnection();
1743 EXPECT_FALSE(caller->SetLocalDescription(caller->CreateRollback()));
1744 EXPECT_FALSE(caller->SetRemoteDescription(caller->CreateRollback()));
1745}
1746
1747TEST_F(PeerConnectionJsepTest, RollbackToStableStateAndClearLocalOffer) {
1748 auto caller = CreatePeerConnection();
1749 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
1750 EXPECT_TRUE(caller->SetLocalDescription(caller->CreateRollback()));
1751 EXPECT_EQ(caller->signaling_state(), PeerConnectionInterface::kStable);
1752 EXPECT_EQ(caller->pc()->pending_local_description(), nullptr);
1753
1754 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
1755 EXPECT_TRUE(caller->SetRemoteDescription(caller->CreateRollback()));
1756 EXPECT_EQ(caller->signaling_state(), PeerConnectionInterface::kStable);
1757 EXPECT_EQ(caller->pc()->pending_local_description(), nullptr);
1758}
1759
1760TEST_F(PeerConnectionJsepTest, RollbackToStableStateAndClearRemoteOffer) {
1761 auto caller = CreatePeerConnection();
1762 auto callee = CreatePeerConnection();
1763 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1764 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
1765 EXPECT_EQ(callee->signaling_state(), PeerConnectionInterface::kStable);
1766 EXPECT_EQ(callee->pc()->pending_remote_description(), nullptr);
1767
1768 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1769 EXPECT_TRUE(callee->SetLocalDescription(caller->CreateRollback()));
1770 EXPECT_EQ(callee->signaling_state(), PeerConnectionInterface::kStable);
1771 EXPECT_EQ(callee->pc()->pending_remote_description(), nullptr);
1772}
1773
Eldar Relloead0ec92019-10-21 23:01:31 +03001774TEST_F(PeerConnectionJsepTest, RollbackImplicitly) {
Eldar Rello5ab79e62019-10-09 18:29:44 +03001775 RTCConfiguration config;
1776 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
1777 config.enable_implicit_rollback = true;
1778 auto caller = CreatePeerConnection(config);
1779 auto callee = CreatePeerConnection(config);
1780 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
1781 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1782 EXPECT_EQ(callee->signaling_state(),
1783 PeerConnectionInterface::kHaveRemoteOffer);
Eldar Relloead0ec92019-10-21 23:01:31 +03001784 EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal());
Henrik Boströme574a312020-08-25 10:20:11 +02001785 EXPECT_FALSE(callee->observer()->legacy_renegotiation_needed());
1786 EXPECT_FALSE(callee->observer()->has_negotiation_needed_event());
Eldar Rello5ab79e62019-10-09 18:29:44 +03001787}
1788
Eldar Relloead0ec92019-10-21 23:01:31 +03001789TEST_F(PeerConnectionJsepTest, RollbackImplicitlyNegotatiationNotNeeded) {
1790 RTCConfiguration config;
1791 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
1792 config.enable_implicit_rollback = true;
1793 auto caller = CreatePeerConnection(config);
1794 auto callee = CreatePeerConnection(config);
1795 caller->AddAudioTrack("a");
1796 callee->AddAudioTrack("b");
1797 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
Henrik Boströme574a312020-08-25 10:20:11 +02001798 callee->observer()->clear_legacy_renegotiation_needed();
1799 callee->observer()->clear_latest_negotiation_needed_event();
Eldar Relloead0ec92019-10-21 23:01:31 +03001800 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1801 EXPECT_EQ(callee->signaling_state(),
1802 PeerConnectionInterface::kHaveRemoteOffer);
1803 EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal());
1804 // No negotiation needed as track got attached in the answer.
Henrik Boströme574a312020-08-25 10:20:11 +02001805 EXPECT_FALSE(callee->observer()->legacy_renegotiation_needed());
1806 EXPECT_FALSE(callee->observer()->has_negotiation_needed_event());
Eldar Relloead0ec92019-10-21 23:01:31 +03001807 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 0u);
1808}
1809
1810TEST_F(PeerConnectionJsepTest, RollbackImplicitlyAndNegotiationNeeded) {
1811 RTCConfiguration config;
1812 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
1813 config.enable_implicit_rollback = true;
1814 auto caller = CreatePeerConnection(config);
1815 auto callee = CreatePeerConnection(config);
1816 callee->AddAudioTrack("a");
1817 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
Henrik Boströme574a312020-08-25 10:20:11 +02001818 callee->observer()->clear_legacy_renegotiation_needed();
1819 callee->observer()->clear_latest_negotiation_needed_event();
Eldar Relloead0ec92019-10-21 23:01:31 +03001820 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1821 EXPECT_EQ(callee->signaling_state(),
1822 PeerConnectionInterface::kHaveRemoteOffer);
Henrik Boströme574a312020-08-25 10:20:11 +02001823 EXPECT_FALSE(callee->observer()->legacy_renegotiation_needed());
1824 EXPECT_FALSE(callee->observer()->has_negotiation_needed_event());
Eldar Relloead0ec92019-10-21 23:01:31 +03001825 EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal());
Henrik Boströme574a312020-08-25 10:20:11 +02001826 EXPECT_TRUE(callee->observer()->legacy_renegotiation_needed());
1827 EXPECT_TRUE(callee->observer()->has_negotiation_needed_event());
Eldar Relloead0ec92019-10-21 23:01:31 +03001828 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 0u);
1829}
1830
1831TEST_F(PeerConnectionJsepTest, AttemptToRollbackImplicitly) {
Eldar Rello5ab79e62019-10-09 18:29:44 +03001832 RTCConfiguration config;
1833 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
1834 config.enable_implicit_rollback = true;
1835 auto caller = CreatePeerConnection(config);
1836 auto callee = CreatePeerConnection(config);
1837 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
1838 EXPECT_FALSE(callee->SetRemoteDescription(
1839 CreateSessionDescription(SdpType::kOffer, "invalid sdp")));
1840 EXPECT_EQ(callee->signaling_state(),
1841 PeerConnectionInterface::kHaveLocalOffer);
1842}
1843
1844TEST_F(PeerConnectionJsepTest, RollbackRemovesTransceiver) {
1845 auto caller = CreatePeerConnection();
1846 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1847 auto callee = CreatePeerConnection();
1848 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
Eldar Relloead0ec92019-10-21 23:01:31 +03001849 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
Eldar Rello5ab79e62019-10-09 18:29:44 +03001850 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
Eldar Relloead0ec92019-10-21 23:01:31 +03001851 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 0u);
1852 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 1u);
Eldar Rello5ab79e62019-10-09 18:29:44 +03001853}
1854
1855TEST_F(PeerConnectionJsepTest, RollbackKeepsTransceiverAndClearsMid) {
1856 auto caller = CreatePeerConnection();
1857 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1858 auto callee = CreatePeerConnection();
1859 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1860 callee->AddAudioTrack("a");
Eldar Relloead0ec92019-10-21 23:01:31 +03001861 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
Eldar Rello5ab79e62019-10-09 18:29:44 +03001862 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
1863 // Transceiver can't be removed as track was added to it.
Eldar Relloead0ec92019-10-21 23:01:31 +03001864 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
Eldar Rello5ab79e62019-10-09 18:29:44 +03001865 // Mid got cleared to make it reusable.
1866 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), absl::nullopt);
1867 // Transceiver should be counted as addTrack-created after rollback.
1868 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
Eldar Relloead0ec92019-10-21 23:01:31 +03001869 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
1870 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 1u);
Eldar Rello5ab79e62019-10-09 18:29:44 +03001871}
1872
Eldar Rello353a7182019-11-25 18:49:44 +02001873TEST_F(PeerConnectionJsepTest,
1874 RollbackKeepsTransceiverAfterAddTrackEvenWhenTrackIsNulled) {
1875 auto caller = CreatePeerConnection();
1876 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1877 auto callee = CreatePeerConnection();
1878 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1879 callee->AddAudioTrack("a");
1880 callee->pc()->GetTransceivers()[0]->sender()->SetTrack(nullptr);
1881 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->sender()->track(), nullptr);
1882 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
1883 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
1884 // Transceiver can't be removed as track was added to it.
1885 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
1886 // Mid got cleared to make it reusable.
1887 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), absl::nullopt);
1888 // Transceiver should be counted as addTrack-created after rollback.
1889 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1890 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
1891 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 1u);
1892}
1893
Eldar Rello5ab79e62019-10-09 18:29:44 +03001894TEST_F(PeerConnectionJsepTest, RollbackRestoresMid) {
1895 auto caller = CreatePeerConnection();
1896 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1897 auto callee = CreatePeerConnection();
1898 callee->AddAudioTrack("a");
1899 auto offer = callee->CreateOffer();
1900 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
Eldar Relloead0ec92019-10-21 23:01:31 +03001901 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
Eldar Rello5ab79e62019-10-09 18:29:44 +03001902 EXPECT_NE(callee->pc()->GetTransceivers()[0]->mid(), absl::nullopt);
1903 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
1904 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), absl::nullopt);
1905 EXPECT_TRUE(callee->SetLocalDescription(std::move(offer)));
1906}
1907
1908TEST_F(PeerConnectionJsepTest, RollbackRestoresMidAndRemovesTransceiver) {
1909 auto callee = CreatePeerConnection();
1910 callee->AddVideoTrack("a");
1911 auto offer = callee->CreateOffer();
1912 auto caller = CreatePeerConnection();
1913 caller->AddAudioTrack("b");
1914 caller->AddVideoTrack("c");
1915 auto mid = callee->pc()->GetTransceivers()[0]->mid();
1916 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
Eldar Relloead0ec92019-10-21 23:01:31 +03001917 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 2u);
Eldar Rello5ab79e62019-10-09 18:29:44 +03001918 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
Eldar Relloead0ec92019-10-21 23:01:31 +03001919 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
Eldar Rello5ab79e62019-10-09 18:29:44 +03001920 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), mid);
1921 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->media_type(),
1922 cricket::MEDIA_TYPE_VIDEO);
1923 EXPECT_TRUE(callee->SetLocalDescription(std::move(offer)));
Eldar Relloead0ec92019-10-21 23:01:31 +03001924 EXPECT_EQ(callee->observer()->remove_track_events_.size(),
1925 callee->observer()->add_track_events_.size());
1926}
1927
1928TEST_F(PeerConnectionJsepTest, RollbackHasNoEffectOnStableTransceivers) {
1929 auto callee = CreatePeerConnection();
1930 callee->AddVideoTrack("a");
1931 auto caller = CreatePeerConnection();
1932 caller->AddAudioTrack("b");
1933 caller->AddVideoTrack("c");
1934 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1935 EXPECT_TRUE(
1936 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1937 // In stable don't add or remove anything.
Henrik Boströme574a312020-08-25 10:20:11 +02001938 callee->observer()->clear_legacy_renegotiation_needed();
1939 callee->observer()->clear_latest_negotiation_needed_event();
Eldar Relloead0ec92019-10-21 23:01:31 +03001940 size_t transceiver_count = callee->pc()->GetTransceivers().size();
1941 auto mid_0 = callee->pc()->GetTransceivers()[0]->mid();
1942 auto mid_1 = callee->pc()->GetTransceivers()[1]->mid();
1943 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1944 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
1945 EXPECT_EQ(callee->pc()->GetTransceivers().size(), transceiver_count);
1946 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), mid_0);
1947 EXPECT_EQ(callee->pc()->GetTransceivers()[1]->mid(), mid_1);
1948 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 0u);
Henrik Boströme574a312020-08-25 10:20:11 +02001949 EXPECT_FALSE(callee->observer()->legacy_renegotiation_needed());
1950 EXPECT_FALSE(callee->observer()->has_negotiation_needed_event());
Eldar Rello5ab79e62019-10-09 18:29:44 +03001951}
1952
1953TEST_F(PeerConnectionJsepTest, ImplicitlyRollbackTransceiversWithSameMids) {
1954 RTCConfiguration config;
1955 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
1956 config.enable_implicit_rollback = true;
1957 auto caller = CreatePeerConnection(config);
1958 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
1959 auto callee = CreatePeerConnection(config);
1960 callee->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
1961 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
1962 auto initial_mid = callee->pc()->GetTransceivers()[0]->mid();
1963 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
Eldar Relloead0ec92019-10-21 23:01:31 +03001964 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 2u);
Eldar Rello5ab79e62019-10-09 18:29:44 +03001965 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), absl::nullopt);
1966 EXPECT_EQ(callee->pc()->GetTransceivers()[1]->mid(),
1967 caller->pc()->GetTransceivers()[0]->mid());
1968 EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal()); // Go to stable.
1969 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
1970 EXPECT_NE(callee->pc()->GetTransceivers()[0]->mid(), initial_mid);
1971}
1972
1973TEST_F(PeerConnectionJsepTest, RollbackToNegotiatedStableState) {
1974 RTCConfiguration config;
1975 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
1976 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
1977 auto caller = CreatePeerConnection(config);
1978 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1979 auto callee = CreatePeerConnection(config);
1980 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1981 EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal());
1982 caller->AddVideoTrack("a");
1983 callee->AddVideoTrack("b");
1984 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
Eldar Relloead0ec92019-10-21 23:01:31 +03001985 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 2u);
Eldar Rello5ab79e62019-10-09 18:29:44 +03001986 auto audio_transport =
1987 callee->pc()->GetTransceivers()[0]->sender()->dtls_transport();
1988 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
1989 callee->pc()->GetTransceivers()[1]->sender()->dtls_transport());
1990 EXPECT_NE(callee->pc()->GetTransceivers()[1]->sender()->dtls_transport(),
1991 nullptr);
1992 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
1993 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
1994 audio_transport); // Audio must remain working after rollback.
1995 EXPECT_EQ(callee->pc()->GetTransceivers()[1]->sender()->dtls_transport(),
1996 nullptr);
1997 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1998
1999 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
2000 audio_transport); // Audio transport is still the same.
2001}
2002
Eldar Rello353a7182019-11-25 18:49:44 +02002003TEST_F(PeerConnectionJsepTest, RollbackHasToDestroyTransport) {
2004 RTCConfiguration config;
2005 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
2006 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
2007 auto pc = CreatePeerConnection(config);
2008 pc->AddAudioTrack("a");
2009 pc->AddVideoTrack("b");
2010 EXPECT_TRUE(pc->CreateOfferAndSetAsLocal());
2011 auto offer = pc->CreateOffer();
2012 EXPECT_EQ(pc->pc()->GetTransceivers().size(), 2u);
2013 auto audio_transport =
2014 pc->pc()->GetTransceivers()[0]->sender()->dtls_transport();
2015 EXPECT_EQ(pc->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
2016 pc->pc()->GetTransceivers()[1]->sender()->dtls_transport());
2017 EXPECT_NE(pc->pc()->GetTransceivers()[1]->sender()->dtls_transport(),
2018 nullptr);
2019 EXPECT_TRUE(pc->SetRemoteDescription(pc->CreateRollback()));
2020 EXPECT_TRUE(pc->SetLocalDescription(std::move(offer)));
2021 EXPECT_NE(pc->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
2022 nullptr);
2023 EXPECT_NE(pc->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
2024 audio_transport);
2025}
2026
Eldar Relloead0ec92019-10-21 23:01:31 +03002027TEST_F(PeerConnectionJsepTest, RollbackLocalDirectionChange) {
2028 auto caller = CreatePeerConnection();
2029 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
2030 auto callee = CreatePeerConnection();
2031 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2032 EXPECT_TRUE(
2033 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
2034 callee->AddAudioTrack("a");
Harald Alvestrand6060df52020-08-11 09:54:02 +02002035 callee->pc()->GetTransceivers()[0]->SetDirectionWithError(
Eldar Relloead0ec92019-10-21 23:01:31 +03002036 RtpTransceiverDirection::kSendOnly);
2037 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2038 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
2039 auto audio_transport =
2040 callee->pc()->GetTransceivers()[0]->receiver()->dtls_transport();
2041 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
2042 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->direction(),
2043 RtpTransceiverDirection::kSendOnly);
2044 // One way audio must remain working after rollback as local direction change
2045 // comes in effect after completing full negotiation round.
2046 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->receiver()->dtls_transport(),
2047 audio_transport);
2048}
2049
2050TEST_F(PeerConnectionJsepTest, RollbackRemoteDirectionChange) {
2051 auto caller = CreatePeerConnection();
2052 auto caller_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
2053 auto callee = CreatePeerConnection();
2054 callee->AddAudioTrack("a");
2055 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2056 EXPECT_TRUE(
2057 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
2058 // In stable make remote audio receive only.
Harald Alvestrand6060df52020-08-11 09:54:02 +02002059 caller_transceiver->SetDirectionWithError(RtpTransceiverDirection::kRecvOnly);
Eldar Relloead0ec92019-10-21 23:01:31 +03002060 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2061 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
2062 // The direction attribute is not modified by the offer.
2063 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->direction(),
2064 RtpTransceiverDirection::kSendRecv);
2065 auto audio_transport =
2066 callee->pc()->GetTransceivers()[0]->sender()->dtls_transport();
2067 EXPECT_EQ(callee->observer()->add_track_events_.size(), 1u);
2068 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 1u);
2069 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
2070 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
2071 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->direction(),
2072 RtpTransceiverDirection::kSendRecv);
2073 // One way audio must remain working after rollback.
2074 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
2075 audio_transport);
2076 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 1u);
2077}
2078
Eldar Rello5ab79e62019-10-09 18:29:44 +03002079TEST_F(PeerConnectionJsepTest, RollbackAfterMultipleSLD) {
2080 auto callee = CreatePeerConnection();
2081 callee->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
2082 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2083 callee->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2084 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
Henrik Boströme574a312020-08-25 10:20:11 +02002085 callee->observer()->clear_legacy_renegotiation_needed();
2086 callee->observer()->clear_latest_negotiation_needed_event();
Eldar Rello5ab79e62019-10-09 18:29:44 +03002087 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
Henrik Boströme574a312020-08-25 10:20:11 +02002088 EXPECT_TRUE(callee->observer()->legacy_renegotiation_needed());
2089 EXPECT_TRUE(callee->observer()->has_negotiation_needed_event());
Eldar Relloead0ec92019-10-21 23:01:31 +03002090 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 2u);
Eldar Rello5ab79e62019-10-09 18:29:44 +03002091 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), absl::nullopt);
2092 EXPECT_EQ(callee->pc()->GetTransceivers()[1]->mid(), absl::nullopt);
2093}
2094
2095TEST_F(PeerConnectionJsepTest, NoRollbackNeeded) {
2096 auto caller = CreatePeerConnection();
2097 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
2098 auto callee = CreatePeerConnection();
2099 callee->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
2100 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
2101 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
2102 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2103 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2104}
2105
Eldar Rello353a7182019-11-25 18:49:44 +02002106TEST_F(PeerConnectionJsepTest, RollbackMultipleStreamChanges) {
2107 auto callee = CreatePeerConnection();
2108 auto caller = CreatePeerConnection();
2109 caller->AddAudioTrack("a_1", {"id_1"});
2110 caller->AddVideoTrack("v_0", {"id_0"}); // Provide an extra stream id.
2111 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2112 EXPECT_TRUE(
2113 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
2114 caller->pc()->GetTransceivers()[0]->sender()->SetStreams({"id_2"});
2115 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2116 caller->pc()->GetTransceivers()[0]->sender()->SetStreams({"id_3"});
2117 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2118 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->receiver()->stream_ids()[0],
2119 "id_3");
2120 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
2121 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->receiver()->stream_ids().size(),
2122 1u);
2123 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->receiver()->stream_ids()[0],
2124 "id_1");
2125}
2126
Eldar Rellod85ea752020-02-19 20:41:07 +02002127TEST_F(PeerConnectionJsepTest, DataChannelImplicitRollback) {
2128 RTCConfiguration config;
2129 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
2130 config.enable_implicit_rollback = true;
2131 auto caller = CreatePeerConnection(config);
2132 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2133 auto callee = CreatePeerConnection(config);
2134 callee->CreateDataChannel("dummy");
2135 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2136 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2137 EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal());
Henrik Boströme574a312020-08-25 10:20:11 +02002138 EXPECT_TRUE(callee->observer()->legacy_renegotiation_needed());
2139 EXPECT_TRUE(callee->observer()->has_negotiation_needed_event());
Eldar Rellod85ea752020-02-19 20:41:07 +02002140 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2141}
2142
2143TEST_F(PeerConnectionJsepTest, RollbackRemoteDataChannelThenAddTransceiver) {
2144 auto caller = CreatePeerConnection();
2145 auto callee = CreatePeerConnection();
2146 caller->CreateDataChannel("dummy");
2147 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2148 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
2149 callee->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2150 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2151}
2152
2153TEST_F(PeerConnectionJsepTest,
2154 RollbackRemoteDataChannelThenAddTransceiverAndDataChannel) {
2155 auto caller = CreatePeerConnection();
2156 auto callee = CreatePeerConnection();
2157 caller->CreateDataChannel("dummy");
2158 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2159 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
2160 callee->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2161 callee->CreateDataChannel("dummy");
2162 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2163}
2164
2165TEST_F(PeerConnectionJsepTest, RollbackRemoteDataChannelThenAddDataChannel) {
2166 auto caller = CreatePeerConnection();
2167 auto callee = CreatePeerConnection();
2168 caller->CreateDataChannel("dummy");
2169 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2170 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
2171 callee->CreateDataChannel("dummy");
2172 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2173}
2174
2175TEST_F(PeerConnectionJsepTest, RollbackRemoteTransceiverThenAddDataChannel) {
2176 auto caller = CreatePeerConnection();
2177 auto callee = CreatePeerConnection();
2178 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2179 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2180 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
2181 callee->CreateDataChannel("dummy");
2182 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2183}
2184
2185TEST_F(PeerConnectionJsepTest,
2186 RollbackRemoteTransceiverThenAddDataChannelAndTransceiver) {
2187 auto caller = CreatePeerConnection();
2188 auto callee = CreatePeerConnection();
2189 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2190 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2191 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
2192 callee->CreateDataChannel("dummy");
2193 callee->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2194 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2195}
2196
Eldar Rellod9ebe012020-03-18 20:41:45 +02002197TEST_F(PeerConnectionJsepTest, RollbackRtpDataChannel) {
2198 RTCConfiguration config;
2199 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
2200 config.enable_rtp_data_channel = true;
2201 auto pc = CreatePeerConnection(config);
2202 pc->CreateDataChannel("dummy");
2203 auto offer = pc->CreateOffer();
2204 EXPECT_TRUE(pc->CreateOfferAndSetAsLocal());
2205 EXPECT_TRUE(pc->SetRemoteDescription(pc->CreateRollback()));
2206 EXPECT_TRUE(pc->SetLocalDescription(std::move(offer)));
2207}
2208
Steve Antondcc3c022017-12-22 16:02:54 -08002209} // namespace webrtc