blob: 66581ca8525a76db60dbaa397a52562813715ad1 [file] [log] [blame]
Steve Antondcc3c022017-12-22 16:02:54 -08001/*
2 * Copyright 2017 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Mirko Bonadei317a1f02019-09-17 17:06:18 +020011#include <memory>
12
Danil Chapovalov9da25bd2019-06-20 10:19:42 +020013#include "api/task_queue/default_task_queue_factory.h"
Erik Språngceb44952020-09-22 11:36:35 +020014#include "api/transport/field_trial_based_config.h"
Steve Anton10542f22019-01-11 09:11:00 -080015#include "media/engine/webrtc_media_engine.h"
Danil Chapovalov9da25bd2019-06-20 10:19:42 +020016#include "media/engine/webrtc_media_engine_defaults.h"
Steve Anton10542f22019-01-11 09:11:00 -080017#include "pc/media_session.h"
18#include "pc/peer_connection_factory.h"
19#include "pc/peer_connection_wrapper.h"
20#include "pc/sdp_utils.h"
Steve Antondcc3c022017-12-22 16:02:54 -080021#ifdef WEBRTC_ANDROID
Steve Anton10542f22019-01-11 09:11:00 -080022#include "pc/test/android_test_initializer.h"
Steve Antondcc3c022017-12-22 16:02:54 -080023#endif
Steve Anton10542f22019-01-11 09:11:00 -080024#include "pc/test/fake_audio_capture_module.h"
Steve Antondcc3c022017-12-22 16:02:54 -080025#include "rtc_base/gunit.h"
Steve Anton10542f22019-01-11 09:11:00 -080026#include "rtc_base/virtual_socket_server.h"
Steve Antondcc3c022017-12-22 16:02:54 -080027#include "test/gmock.h"
Per Kjellander2bca0082020-08-28 09:15:15 +020028#include "test/pc/sctp/fake_sctp_transport.h"
Steve Antondcc3c022017-12-22 16:02:54 -080029
30// This file contains tests that ensure the PeerConnection's implementation of
31// CreateOffer/CreateAnswer/SetLocalDescription/SetRemoteDescription conform
32// to the JavaScript Session Establishment Protocol (JSEP).
33// For now these semantics are only available when configuring the
34// PeerConnection with Unified Plan, but eventually that will be the default.
35
36namespace webrtc {
37
38using cricket::MediaContentDescription;
39using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
Steve Antondcc3c022017-12-22 16:02:54 -080040using ::testing::Combine;
41using ::testing::ElementsAre;
Steve Antonef65ef12018-01-10 17:15:20 -080042using ::testing::UnorderedElementsAre;
Jonas Olssona4d87372019-07-05 19:08:33 +020043using ::testing::Values;
Steve Antondcc3c022017-12-22 16:02:54 -080044
Per Kjellander2bca0082020-08-28 09:15:15 +020045PeerConnectionFactoryDependencies CreatePeerConnectionFactoryDependencies() {
46 PeerConnectionFactoryDependencies dependencies;
47 dependencies.worker_thread = rtc::Thread::Current();
48 dependencies.network_thread = rtc::Thread::Current();
49 dependencies.signaling_thread = rtc::Thread::Current();
50 dependencies.task_queue_factory = CreateDefaultTaskQueueFactory();
Erik Språngceb44952020-09-22 11:36:35 +020051 dependencies.trials = std::make_unique<FieldTrialBasedConfig>();
Per Kjellander2bca0082020-08-28 09:15:15 +020052 cricket::MediaEngineDependencies media_deps;
53 media_deps.task_queue_factory = dependencies.task_queue_factory.get();
54 media_deps.adm = FakeAudioCaptureModule::Create();
Erik Språngceb44952020-09-22 11:36:35 +020055 media_deps.trials = dependencies.trials.get();
Per Kjellander2bca0082020-08-28 09:15:15 +020056 SetMediaEngineDefaults(&media_deps);
57 dependencies.media_engine = cricket::CreateMediaEngine(std::move(media_deps));
58 dependencies.call_factory = CreateCallFactory();
59 dependencies.sctp_factory = std::make_unique<FakeSctpTransportFactory>();
60 return dependencies;
61}
Steve Antonfa2260d2017-12-28 16:38:23 -080062
Steve Antondcc3c022017-12-22 16:02:54 -080063class PeerConnectionJsepTest : public ::testing::Test {
64 protected:
65 typedef std::unique_ptr<PeerConnectionWrapper> WrapperPtr;
66
67 PeerConnectionJsepTest()
68 : vss_(new rtc::VirtualSocketServer()), main_(vss_.get()) {
69#ifdef WEBRTC_ANDROID
70 InitializeAndroidObjects();
71#endif
Steve Antondcc3c022017-12-22 16:02:54 -080072 }
73
74 WrapperPtr CreatePeerConnection() {
75 RTCConfiguration config;
76 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
77 return CreatePeerConnection(config);
78 }
79
80 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
Per Kjellander2bca0082020-08-28 09:15:15 +020081 rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory =
82 CreateModularPeerConnectionFactory(
83 CreatePeerConnectionFactoryDependencies());
Mirko Bonadei317a1f02019-09-17 17:06:18 +020084 auto observer = std::make_unique<MockPeerConnectionObserver>();
Steve Antonfa2260d2017-12-28 16:38:23 -080085 auto pc = pc_factory->CreatePeerConnection(config, nullptr, nullptr,
86 observer.get());
Steve Antondcc3c022017-12-22 16:02:54 -080087 if (!pc) {
88 return nullptr;
89 }
90
Yves Gerey4e933292018-10-31 15:36:05 +010091 observer->SetPeerConnectionInterface(pc.get());
Mirko Bonadei317a1f02019-09-17 17:06:18 +020092 return std::make_unique<PeerConnectionWrapper>(pc_factory, pc,
93 std::move(observer));
Steve Antondcc3c022017-12-22 16:02:54 -080094 }
95
96 std::unique_ptr<rtc::VirtualSocketServer> vss_;
97 rtc::AutoSocketServerThread main_;
Steve Antondcc3c022017-12-22 16:02:54 -080098};
99
100// Tests for JSEP initial offer generation.
101
102// Test that an offer created by a PeerConnection with no transceivers generates
103// no media sections.
104TEST_F(PeerConnectionJsepTest, EmptyInitialOffer) {
105 auto caller = CreatePeerConnection();
Steve Antonfa2260d2017-12-28 16:38:23 -0800106
Steve Antondcc3c022017-12-22 16:02:54 -0800107 auto offer = caller->CreateOffer();
Steve Antonfa2260d2017-12-28 16:38:23 -0800108 ASSERT_EQ(0u, offer->description()->contents().size());
Steve Antondcc3c022017-12-22 16:02:54 -0800109}
110
111// Test that an initial offer with one audio track generates one audio media
112// section.
113TEST_F(PeerConnectionJsepTest, AudioOnlyInitialOffer) {
114 auto caller = CreatePeerConnection();
115 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
Steve Antondcc3c022017-12-22 16:02:54 -0800116
Steve Antonfa2260d2017-12-28 16:38:23 -0800117 auto offer = caller->CreateOffer();
Steve Antondcc3c022017-12-22 16:02:54 -0800118 auto contents = offer->description()->contents();
119 ASSERT_EQ(1u, contents.size());
120 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, contents[0].media_description()->type());
121}
122
123// Test than an initial offer with one video track generates one video media
124// section
125TEST_F(PeerConnectionJsepTest, VideoOnlyInitialOffer) {
126 auto caller = CreatePeerConnection();
127 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
Steve Antondcc3c022017-12-22 16:02:54 -0800128
Steve Antonfa2260d2017-12-28 16:38:23 -0800129 auto offer = caller->CreateOffer();
Steve Antondcc3c022017-12-22 16:02:54 -0800130 auto contents = offer->description()->contents();
131 ASSERT_EQ(1u, contents.size());
132 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, contents[0].media_description()->type());
133}
134
Steve Antonfa2260d2017-12-28 16:38:23 -0800135// Test that an initial offer with one data channel generates one data media
136// section.
137TEST_F(PeerConnectionJsepTest, DataOnlyInitialOffer) {
138 auto caller = CreatePeerConnection();
139 caller->CreateDataChannel("dc");
140
141 auto offer = caller->CreateOffer();
142 auto contents = offer->description()->contents();
143 ASSERT_EQ(1u, contents.size());
144 EXPECT_EQ(cricket::MEDIA_TYPE_DATA, contents[0].media_description()->type());
145}
146
147// Test that creating multiple data channels only results in one data section
148// generated in the offer.
149TEST_F(PeerConnectionJsepTest, MultipleDataChannelsCreateOnlyOneDataSection) {
150 auto caller = CreatePeerConnection();
151 caller->CreateDataChannel("first");
152 caller->CreateDataChannel("second");
153 caller->CreateDataChannel("third");
154
155 auto offer = caller->CreateOffer();
156 ASSERT_EQ(1u, offer->description()->contents().size());
157}
158
Steve Antondcc3c022017-12-22 16:02:54 -0800159// Test that multiple media sections in the initial offer are ordered in the
160// order the transceivers were added to the PeerConnection. This is required by
161// JSEP section 5.2.1.
162TEST_F(PeerConnectionJsepTest, MediaSectionsInInitialOfferOrderedCorrectly) {
163 auto caller = CreatePeerConnection();
164 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
165 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
166 RtpTransceiverInit init;
167 init.direction = RtpTransceiverDirection::kSendOnly;
168 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init);
Steve Antondcc3c022017-12-22 16:02:54 -0800169
Steve Antonfa2260d2017-12-28 16:38:23 -0800170 auto offer = caller->CreateOffer();
Steve Antondcc3c022017-12-22 16:02:54 -0800171 auto contents = offer->description()->contents();
172 ASSERT_EQ(3u, contents.size());
173
174 const MediaContentDescription* media_description1 =
175 contents[0].media_description();
176 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, media_description1->type());
177 EXPECT_EQ(RtpTransceiverDirection::kSendRecv,
178 media_description1->direction());
179
180 const MediaContentDescription* media_description2 =
181 contents[1].media_description();
182 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, media_description2->type());
183 EXPECT_EQ(RtpTransceiverDirection::kSendRecv,
184 media_description2->direction());
185
186 const MediaContentDescription* media_description3 =
187 contents[2].media_description();
188 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, media_description3->type());
189 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
190 media_description3->direction());
191}
192
193// Test that media sections in the initial offer have different mids.
194TEST_F(PeerConnectionJsepTest, MediaSectionsInInitialOfferHaveDifferentMids) {
195 auto caller = CreatePeerConnection();
196 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
197 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
Steve Antonfa2260d2017-12-28 16:38:23 -0800198
Steve Antondcc3c022017-12-22 16:02:54 -0800199 auto offer = caller->CreateOffer();
Steve Antondcc3c022017-12-22 16:02:54 -0800200 auto contents = offer->description()->contents();
201 ASSERT_EQ(2u, contents.size());
202 EXPECT_NE(contents[0].name, contents[1].name);
203}
204
205TEST_F(PeerConnectionJsepTest,
206 StoppedTransceiverHasNoMediaSectionInInitialOffer) {
207 auto caller = CreatePeerConnection();
208 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
Harald Alvestrand6060df52020-08-11 09:54:02 +0200209 transceiver->StopInternal();
Steve Antondcc3c022017-12-22 16:02:54 -0800210
211 auto offer = caller->CreateOffer();
212 EXPECT_EQ(0u, offer->description()->contents().size());
213}
214
215// Tests for JSEP SetLocalDescription with a local offer.
216
217TEST_F(PeerConnectionJsepTest, SetLocalEmptyOfferCreatesNoTransceivers) {
218 auto caller = CreatePeerConnection();
Steve Antonfa2260d2017-12-28 16:38:23 -0800219
Steve Antondcc3c022017-12-22 16:02:54 -0800220 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
221
222 EXPECT_THAT(caller->pc()->GetTransceivers(), ElementsAre());
223 EXPECT_THAT(caller->pc()->GetSenders(), ElementsAre());
224 EXPECT_THAT(caller->pc()->GetReceivers(), ElementsAre());
225}
226
227TEST_F(PeerConnectionJsepTest, SetLocalOfferSetsTransceiverMid) {
228 auto caller = CreatePeerConnection();
229 auto audio_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
230 auto video_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
231
232 auto offer = caller->CreateOffer();
233 std::string audio_mid = offer->description()->contents()[0].name;
234 std::string video_mid = offer->description()->contents()[1].name;
235
236 ASSERT_TRUE(caller->SetLocalDescription(std::move(offer)));
237
238 EXPECT_EQ(audio_mid, audio_transceiver->mid());
239 EXPECT_EQ(video_mid, video_transceiver->mid());
240}
241
242// Tests for JSEP SetRemoteDescription with a remote offer.
243
244// Test that setting a remote offer with sendrecv audio and video creates two
245// transceivers, one for receiving audio and one for receiving video.
246TEST_F(PeerConnectionJsepTest, SetRemoteOfferCreatesTransceivers) {
247 auto caller = CreatePeerConnection();
248 auto caller_audio = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
249 auto caller_video = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
250 auto callee = CreatePeerConnection();
251
252 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
253
254 auto transceivers = callee->pc()->GetTransceivers();
255 ASSERT_EQ(2u, transceivers.size());
Steve Anton1bc97162018-06-25 14:04:01 -0700256
Steve Anton69470252018-02-09 11:43:08 -0800257 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, transceivers[0]->media_type());
Steve Antondcc3c022017-12-22 16:02:54 -0800258 EXPECT_EQ(caller_audio->mid(), transceivers[0]->mid());
259 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly, transceivers[0]->direction());
Steve Anton1bc97162018-06-25 14:04:01 -0700260 EXPECT_EQ(0u, transceivers[0]->sender()->stream_ids().size());
261
Steve Anton69470252018-02-09 11:43:08 -0800262 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, transceivers[1]->media_type());
Steve Antondcc3c022017-12-22 16:02:54 -0800263 EXPECT_EQ(caller_video->mid(), transceivers[1]->mid());
264 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly, transceivers[1]->direction());
Steve Anton1bc97162018-06-25 14:04:01 -0700265 EXPECT_EQ(0u, transceivers[1]->sender()->stream_ids().size());
Steve Antondcc3c022017-12-22 16:02:54 -0800266}
267
268// Test that setting a remote offer with an audio track will reuse the
269// transceiver created for a local audio track added by AddTrack.
270// This is specified in JSEP section 5.10 (Applying a Remote Description). The
271// intent is to preserve backwards compatibility with clients who only use the
272// AddTrack API.
273TEST_F(PeerConnectionJsepTest, SetRemoteOfferReusesTransceiverFromAddTrack) {
274 auto caller = CreatePeerConnection();
275 caller->AddAudioTrack("a");
276 auto caller_audio = caller->pc()->GetTransceivers()[0];
277 auto callee = CreatePeerConnection();
278 callee->AddAudioTrack("a");
279
280 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
281
282 auto transceivers = callee->pc()->GetTransceivers();
283 ASSERT_EQ(1u, transceivers.size());
284 EXPECT_EQ(MediaStreamTrackInterface::kAudioKind,
285 transceivers[0]->receiver()->track()->kind());
286 EXPECT_EQ(caller_audio->mid(), transceivers[0]->mid());
287}
288
289// Test that setting a remote offer with an audio track marked sendonly will not
290// reuse a transceiver created by AddTrack. JSEP only allows the transceiver to
291// be reused if the offer direction is sendrecv or recvonly.
292TEST_F(PeerConnectionJsepTest,
293 SetRemoteOfferDoesNotReuseTransceiverIfDirectionSendOnly) {
294 auto caller = CreatePeerConnection();
295 caller->AddAudioTrack("a");
296 auto caller_audio = caller->pc()->GetTransceivers()[0];
Harald Alvestrand6060df52020-08-11 09:54:02 +0200297 caller_audio->SetDirectionWithError(RtpTransceiverDirection::kSendOnly);
Steve Antondcc3c022017-12-22 16:02:54 -0800298 auto callee = CreatePeerConnection();
299 callee->AddAudioTrack("a");
300
301 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
302
303 auto transceivers = callee->pc()->GetTransceivers();
304 ASSERT_EQ(2u, transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200305 EXPECT_EQ(absl::nullopt, transceivers[0]->mid());
Steve Antondcc3c022017-12-22 16:02:54 -0800306 EXPECT_EQ(caller_audio->mid(), transceivers[1]->mid());
307}
308
309// Test that setting a remote offer with an audio track will not reuse a
310// transceiver added by AddTransceiver. The logic for reusing a transceiver is
311// specific to those added by AddTrack and is tested above.
312TEST_F(PeerConnectionJsepTest,
313 SetRemoteOfferDoesNotReuseTransceiverFromAddTransceiver) {
314 auto caller = CreatePeerConnection();
315 caller->AddAudioTrack("a");
316 auto callee = CreatePeerConnection();
317 auto transceiver = callee->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
318
319 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
320
321 auto transceivers = callee->pc()->GetTransceivers();
322 ASSERT_EQ(2u, transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200323 EXPECT_EQ(absl::nullopt, transceivers[0]->mid());
Steve Antondcc3c022017-12-22 16:02:54 -0800324 EXPECT_EQ(caller->pc()->GetTransceivers()[0]->mid(), transceivers[1]->mid());
325 EXPECT_EQ(MediaStreamTrackInterface::kAudioKind,
326 transceivers[1]->receiver()->track()->kind());
327}
328
329// Test that setting a remote offer with an audio track will not reuse a
330// transceiver created for a local video track added by AddTrack.
331TEST_F(PeerConnectionJsepTest,
332 SetRemoteOfferDoesNotReuseTransceiverOfWrongType) {
333 auto caller = CreatePeerConnection();
334 caller->AddAudioTrack("a");
335 auto callee = CreatePeerConnection();
336 auto video_sender = callee->AddVideoTrack("v");
337
338 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
339
340 auto transceivers = callee->pc()->GetTransceivers();
341 ASSERT_EQ(2u, transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200342 EXPECT_EQ(absl::nullopt, transceivers[0]->mid());
Steve Antondcc3c022017-12-22 16:02:54 -0800343 EXPECT_EQ(caller->pc()->GetTransceivers()[0]->mid(), transceivers[1]->mid());
344 EXPECT_EQ(MediaStreamTrackInterface::kAudioKind,
345 transceivers[1]->receiver()->track()->kind());
346}
347
348// Test that setting a remote offer with an audio track will not reuse a
349// stopped transceiver.
350TEST_F(PeerConnectionJsepTest, SetRemoteOfferDoesNotReuseStoppedTransceiver) {
351 auto caller = CreatePeerConnection();
352 caller->AddAudioTrack("a");
353 auto callee = CreatePeerConnection();
354 callee->AddAudioTrack("a");
Harald Alvestrand6060df52020-08-11 09:54:02 +0200355 callee->pc()->GetTransceivers()[0]->StopInternal();
Steve Antondcc3c022017-12-22 16:02:54 -0800356
357 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
358
359 auto transceivers = callee->pc()->GetTransceivers();
Harald Alvestrand936f1af2020-09-22 07:41:50 +0000360 ASSERT_EQ(2u, transceivers.size());
361 // The stopped transceiver is removed in SetLocalDescription(answer)
362 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
363 transceivers = callee->pc()->GetTransceivers();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200364 ASSERT_EQ(1u, transceivers.size());
365 EXPECT_EQ(caller->pc()->GetTransceivers()[0]->mid(), transceivers[0]->mid());
366 EXPECT_FALSE(transceivers[0]->stopped());
Steve Antondcc3c022017-12-22 16:02:54 -0800367}
368
369// Test that audio and video transceivers created on the remote side with
370// AddTrack will all be reused if there is the same number of audio/video tracks
371// in the remote offer. Additionally, this tests that transceivers are
372// successfully matched even if they are in a different order on the remote
373// side.
374TEST_F(PeerConnectionJsepTest, SetRemoteOfferReusesTransceiversOfBothTypes) {
375 auto caller = CreatePeerConnection();
376 caller->AddVideoTrack("v");
377 caller->AddAudioTrack("a");
378 auto callee = CreatePeerConnection();
379 callee->AddAudioTrack("a");
380 callee->AddVideoTrack("v");
381
382 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
383
384 auto caller_transceivers = caller->pc()->GetTransceivers();
385 auto callee_transceivers = callee->pc()->GetTransceivers();
386 ASSERT_EQ(2u, callee_transceivers.size());
387 EXPECT_EQ(caller_transceivers[0]->mid(), callee_transceivers[1]->mid());
388 EXPECT_EQ(caller_transceivers[1]->mid(), callee_transceivers[0]->mid());
389}
390
391// Tests for JSEP initial CreateAnswer.
392
393// Test that the answer to a remote offer creates media sections for each
394// offered media in the same order and with the same mids.
395TEST_F(PeerConnectionJsepTest, CreateAnswerHasSameMidsAsOffer) {
396 auto caller = CreatePeerConnection();
397 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
398 auto second_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
399 auto third_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
Steve Antonfa2260d2017-12-28 16:38:23 -0800400 caller->CreateDataChannel("dc");
Steve Antondcc3c022017-12-22 16:02:54 -0800401 auto callee = CreatePeerConnection();
402
Steve Antonfa2260d2017-12-28 16:38:23 -0800403 auto offer = caller->CreateOffer();
404 const auto* offer_data = cricket::GetFirstDataContent(offer->description());
405 ASSERT_TRUE(
406 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
407 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
Steve Antondcc3c022017-12-22 16:02:54 -0800408
409 auto answer = callee->CreateAnswer();
410 auto contents = answer->description()->contents();
Steve Antonfa2260d2017-12-28 16:38:23 -0800411 ASSERT_EQ(4u, contents.size());
Steve Antondcc3c022017-12-22 16:02:54 -0800412 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, contents[0].media_description()->type());
Steve Antonfa2260d2017-12-28 16:38:23 -0800413 EXPECT_EQ(first_transceiver->mid(), contents[0].name);
Steve Antondcc3c022017-12-22 16:02:54 -0800414 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, contents[1].media_description()->type());
Steve Antonfa2260d2017-12-28 16:38:23 -0800415 EXPECT_EQ(second_transceiver->mid(), contents[1].name);
Steve Antondcc3c022017-12-22 16:02:54 -0800416 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, contents[2].media_description()->type());
Steve Antonfa2260d2017-12-28 16:38:23 -0800417 EXPECT_EQ(third_transceiver->mid(), contents[2].name);
418 EXPECT_EQ(cricket::MEDIA_TYPE_DATA, contents[3].media_description()->type());
419 EXPECT_EQ(offer_data->name, contents[3].name);
Steve Antondcc3c022017-12-22 16:02:54 -0800420}
421
422// Test that an answering media section is marked as rejected if the underlying
423// transceiver has been stopped.
424TEST_F(PeerConnectionJsepTest, CreateAnswerRejectsStoppedTransceiver) {
425 auto caller = CreatePeerConnection();
426 caller->AddAudioTrack("a");
427 auto callee = CreatePeerConnection();
428
429 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
430
Harald Alvestrand6060df52020-08-11 09:54:02 +0200431 callee->pc()->GetTransceivers()[0]->StopInternal();
Steve Antondcc3c022017-12-22 16:02:54 -0800432
433 auto answer = callee->CreateAnswer();
434 auto contents = answer->description()->contents();
435 ASSERT_EQ(1u, contents.size());
436 EXPECT_TRUE(contents[0].rejected);
437}
438
439// Test that CreateAnswer will generate media sections which will only send or
440// receive if the offer indicates it can do the reciprocating direction.
441// The full matrix is tested more extensively in MediaSession.
442TEST_F(PeerConnectionJsepTest, CreateAnswerNegotiatesDirection) {
443 auto caller = CreatePeerConnection();
444 RtpTransceiverInit init;
445 init.direction = RtpTransceiverDirection::kSendOnly;
446 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init);
447 auto callee = CreatePeerConnection();
448 callee->AddAudioTrack("a");
449
450 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
451
452 auto answer = callee->CreateAnswer();
453 auto contents = answer->description()->contents();
454 ASSERT_EQ(1u, contents.size());
455 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
456 contents[0].media_description()->direction());
457}
458
459// Tests for JSEP SetLocalDescription with a local answer.
460// Note that these test only the additional behaviors not covered by
461// SetLocalDescription with a local offer.
462
463// Test that SetLocalDescription with an answer sets the current_direction
464// property of the transceivers mentioned in the session description.
465TEST_F(PeerConnectionJsepTest, SetLocalAnswerUpdatesCurrentDirection) {
466 auto caller = CreatePeerConnection();
467 auto caller_audio = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
Harald Alvestrand6060df52020-08-11 09:54:02 +0200468 caller_audio->SetDirectionWithError(RtpTransceiverDirection::kRecvOnly);
Steve Antondcc3c022017-12-22 16:02:54 -0800469 auto callee = CreatePeerConnection();
470 callee->AddAudioTrack("a");
471
472 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
473 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
474
475 auto transceivers = callee->pc()->GetTransceivers();
476 ASSERT_EQ(1u, transceivers.size());
477 // Since the offer was recvonly and the transceiver direction is sendrecv,
478 // the negotiated direction will be sendonly.
479 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
480 transceivers[0]->current_direction());
481}
482
483// Tests for JSEP SetRemoteDescription with a remote answer.
484// Note that these test only the additional behaviors not covered by
485// SetRemoteDescription with a remote offer.
486
487TEST_F(PeerConnectionJsepTest, SetRemoteAnswerUpdatesCurrentDirection) {
488 auto caller = CreatePeerConnection();
489 caller->AddAudioTrack("a");
490 auto callee = CreatePeerConnection();
491 callee->AddAudioTrack("a");
492 auto callee_audio = callee->pc()->GetTransceivers()[0];
Harald Alvestrand6060df52020-08-11 09:54:02 +0200493 callee_audio->SetDirectionWithError(RtpTransceiverDirection::kSendOnly);
Steve Antondcc3c022017-12-22 16:02:54 -0800494
495 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
496 ASSERT_TRUE(
497 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
498
499 auto transceivers = caller->pc()->GetTransceivers();
500 ASSERT_EQ(1u, transceivers.size());
501 // Since the remote transceiver was set to sendonly, the negotiated direction
502 // in the answer would be sendonly which we apply as recvonly to the local
503 // transceiver.
504 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
505 transceivers[0]->current_direction());
506}
507
Stefan Mitic3aa99372022-02-03 04:26:22 -0800508TEST_F(PeerConnectionJsepTest,
509 ChangeDirectionFromRecvOnlyToSendRecvDoesNotBreakVideoNegotiation) {
510 auto caller = CreatePeerConnection();
511 auto caller_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
512 auto callee = CreatePeerConnection();
513 caller_transceiver->SetDirectionWithError(RtpTransceiverDirection::kRecvOnly);
514
515 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
516 ASSERT_TRUE(
517 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
518
519 caller_transceiver->SetDirectionWithError(RtpTransceiverDirection::kSendRecv);
520
521 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
522 ASSERT_TRUE(
523 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
524}
525
526TEST_F(PeerConnectionJsepTest,
527 ChangeDirectionFromRecvOnlyToSendRecvDoesNotBreakAudioNegotiation) {
528 auto caller = CreatePeerConnection();
529 auto caller_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
530 auto callee = CreatePeerConnection();
531 caller_transceiver->SetDirectionWithError(RtpTransceiverDirection::kRecvOnly);
532
533 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
534 ASSERT_TRUE(
535 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
536
537 caller_transceiver->SetDirectionWithError(RtpTransceiverDirection::kSendRecv);
538
539 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
540 ASSERT_TRUE(
541 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
542}
543
Steve Antondcc3c022017-12-22 16:02:54 -0800544// Tests for multiple round trips.
545
546// Test that setting a transceiver with the inactive direction does not stop it
547// on either the caller or the callee.
548TEST_F(PeerConnectionJsepTest, SettingTransceiverInactiveDoesNotStopIt) {
549 auto caller = CreatePeerConnection();
550 caller->AddAudioTrack("a");
551 auto callee = CreatePeerConnection();
552 callee->AddAudioTrack("a");
Harald Alvestrand6060df52020-08-11 09:54:02 +0200553 callee->pc()->GetTransceivers()[0]->SetDirectionWithError(
Steve Antondcc3c022017-12-22 16:02:54 -0800554 RtpTransceiverDirection::kInactive);
555
556 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
557 ASSERT_TRUE(
558 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
559
560 EXPECT_FALSE(caller->pc()->GetTransceivers()[0]->stopped());
561 EXPECT_FALSE(callee->pc()->GetTransceivers()[0]->stopped());
562}
563
564// Test that if a transceiver had been associated and later stopped, then a
565// media section is still generated for it and the media section is marked as
566// rejected.
567TEST_F(PeerConnectionJsepTest,
568 ReOfferMediaSectionForAssociatedStoppedTransceiverIsRejected) {
569 auto caller = CreatePeerConnection();
570 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
571 auto callee = CreatePeerConnection();
572
573 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
574 ASSERT_TRUE(
575 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
576
577 ASSERT_TRUE(transceiver->mid());
Harald Alvestrand6060df52020-08-11 09:54:02 +0200578 transceiver->StopInternal();
Steve Antondcc3c022017-12-22 16:02:54 -0800579
580 auto reoffer = caller->CreateOffer();
581 auto contents = reoffer->description()->contents();
582 ASSERT_EQ(1u, contents.size());
583 EXPECT_TRUE(contents[0].rejected);
584}
585
586// Test that stopping an associated transceiver on the caller side will stop the
587// corresponding transceiver on the remote side when the remote offer is
588// applied.
589TEST_F(PeerConnectionJsepTest,
590 StoppingTransceiverInOfferStopsTransceiverOnRemoteSide) {
591 auto caller = CreatePeerConnection();
592 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
593 auto callee = CreatePeerConnection();
594
595 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
596 ASSERT_TRUE(
597 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
598
Harald Alvestrand6060df52020-08-11 09:54:02 +0200599 transceiver->StopInternal();
Steve Antondcc3c022017-12-22 16:02:54 -0800600
601 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
602
603 auto transceivers = callee->pc()->GetTransceivers();
Harald Alvestrand936f1af2020-09-22 07:41:50 +0000604 EXPECT_EQ(1u, transceivers.size());
605 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
606 transceivers = callee->pc()->GetTransceivers();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200607 EXPECT_EQ(0u, transceivers.size());
Steve Antondcc3c022017-12-22 16:02:54 -0800608}
609
610// Test that CreateOffer will only generate a recycled media section if the
611// transceiver to be recycled has been seen stopped by the other side first.
612TEST_F(PeerConnectionJsepTest,
613 CreateOfferDoesNotRecycleMediaSectionIfFirstStopped) {
614 auto caller = CreatePeerConnection();
615 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
616 auto callee = CreatePeerConnection();
617
618 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
619 ASSERT_TRUE(
620 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
621
622 auto second_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
Harald Alvestrand6060df52020-08-11 09:54:02 +0200623 first_transceiver->StopInternal();
Steve Antondcc3c022017-12-22 16:02:54 -0800624
625 auto reoffer = caller->CreateOffer();
626 auto contents = reoffer->description()->contents();
627 ASSERT_EQ(2u, contents.size());
628 EXPECT_TRUE(contents[0].rejected);
629 EXPECT_FALSE(contents[1].rejected);
630}
631
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800632// Test that the offer/answer and the transceivers are correctly generated and
633// updated when the media section is recycled after the callee stops a
634// transceiver and sends an answer with a 0 port.
635TEST_F(PeerConnectionJsepTest,
636 RecycleMediaSectionWhenStoppingTransceiverOnAnswerer) {
637 auto caller = CreatePeerConnection();
638 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
639 auto callee = CreatePeerConnection();
640
641 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
Harald Alvestrand936f1af2020-09-22 07:41:50 +0000642 std::string first_mid = *first_transceiver->mid();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200643 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
644 callee->pc()->GetTransceivers()[0]->StopInternal();
Harald Alvestrand936f1af2020-09-22 07:41:50 +0000645 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800646 ASSERT_TRUE(
647 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
648 EXPECT_TRUE(first_transceiver->stopped());
Harald Alvestrand936f1af2020-09-22 07:41:50 +0000649 // First transceivers are dissociated on caller side.
650 ASSERT_EQ(absl::nullopt, first_transceiver->mid());
Harald Alvestrand6060df52020-08-11 09:54:02 +0200651 // They are disassociated on callee side.
652 ASSERT_EQ(0u, callee->pc()->GetTransceivers().size());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800653
654 // New offer exchange with new transceivers that recycles the m section
655 // correctly.
656 caller->AddAudioTrack("audio2");
657 callee->AddAudioTrack("audio2");
658 auto offer = caller->CreateOffer();
659 auto offer_contents = offer->description()->contents();
660 std::string second_mid = offer_contents[0].name;
661 ASSERT_EQ(1u, offer_contents.size());
662 EXPECT_FALSE(offer_contents[0].rejected);
663 EXPECT_NE(first_mid, second_mid);
664
665 // Setting the offer on each side will dissociate the first transceivers and
666 // associate the new transceivers.
667 ASSERT_TRUE(
668 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200669 EXPECT_EQ(absl::nullopt, first_transceiver->mid());
Harald Alvestrand6060df52020-08-11 09:54:02 +0200670 ASSERT_EQ(1u, caller->pc()->GetTransceivers().size());
671 EXPECT_EQ(second_mid, caller->pc()->GetTransceivers()[0]->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800672 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
Harald Alvestrand6060df52020-08-11 09:54:02 +0200673 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
674 EXPECT_EQ(second_mid, callee->pc()->GetTransceivers()[0]->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800675
676 // The new answer should also recycle the m section correctly.
677 auto answer = callee->CreateAnswer();
678 auto answer_contents = answer->description()->contents();
679 ASSERT_EQ(1u, answer_contents.size());
680 EXPECT_FALSE(answer_contents[0].rejected);
681 EXPECT_EQ(second_mid, answer_contents[0].name);
682
683 // Finishing the negotiation shouldn't add or dissociate any transceivers.
684 ASSERT_TRUE(
685 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
686 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
687 auto caller_transceivers = caller->pc()->GetTransceivers();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200688 ASSERT_EQ(1u, caller_transceivers.size());
689 EXPECT_EQ(second_mid, caller_transceivers[0]->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800690 auto callee_transceivers = callee->pc()->GetTransceivers();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200691 ASSERT_EQ(1u, callee_transceivers.size());
692 EXPECT_EQ(second_mid, callee_transceivers[0]->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800693}
694
695// Test that creating/setting a local offer that recycles an m= section is
696// idempotent.
697TEST_F(PeerConnectionJsepTest, CreateOfferRecyclesWhenOfferingTwice) {
698 // Do a negotiation with a port 0 for the media section.
699 auto caller = CreatePeerConnection();
700 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
701 auto callee = CreatePeerConnection();
702 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Harald Alvestrand6060df52020-08-11 09:54:02 +0200703 first_transceiver->StopInternal();
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800704 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
705 caller->AddAudioTrack("audio2");
706
707 // Create a new offer that recycles the media section and set it as a local
708 // description.
709 auto offer = caller->CreateOffer();
710 auto offer_contents = offer->description()->contents();
711 ASSERT_EQ(1u, offer_contents.size());
712 EXPECT_FALSE(offer_contents[0].rejected);
713 ASSERT_TRUE(caller->SetLocalDescription(std::move(offer)));
Harald Alvestrand6060df52020-08-11 09:54:02 +0200714 ASSERT_EQ(1u, caller->pc()->GetTransceivers().size());
715 EXPECT_FALSE(caller->pc()->GetTransceivers()[0]->stopped());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800716 std::string second_mid = offer_contents[0].name;
717
718 // Create another new offer and set the local description again without the
719 // rest of any negotation ocurring.
720 auto second_offer = caller->CreateOffer();
721 auto second_offer_contents = second_offer->description()->contents();
722 ASSERT_EQ(1u, second_offer_contents.size());
723 EXPECT_FALSE(second_offer_contents[0].rejected);
724 // The mid shouldn't change.
725 EXPECT_EQ(second_mid, second_offer_contents[0].name);
726
727 ASSERT_TRUE(caller->SetLocalDescription(std::move(second_offer)));
728 // Make sure that the caller's transceivers are associated correctly.
729 auto caller_transceivers = caller->pc()->GetTransceivers();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200730 ASSERT_EQ(1u, caller_transceivers.size());
731 EXPECT_EQ(second_mid, caller_transceivers[0]->mid());
732 EXPECT_FALSE(caller_transceivers[0]->stopped());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800733}
734
Steve Antondcc3c022017-12-22 16:02:54 -0800735// Test that the offer/answer and transceivers for both the caller and callee
736// side are generated/updated correctly when recycling an audio/video media
737// section as a media section of either the same or opposite type.
Steve Anton5c72e712018-12-10 14:25:30 -0800738// Correct recycling works as follows:
739// - The m= section is re-offered with a new MID value and the new media type.
740// - The previously-associated transceiver is dissociated when the new offer is
741// set as a local description on the offerer or as a remote description on
742// the answerer.
743// - The new transceiver is associated with the new MID value.
Steve Antondcc3c022017-12-22 16:02:54 -0800744class RecycleMediaSectionTest
745 : public PeerConnectionJsepTest,
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200746 public ::testing::WithParamInterface<
Steve Antondcc3c022017-12-22 16:02:54 -0800747 std::tuple<cricket::MediaType, cricket::MediaType>> {
748 protected:
749 RecycleMediaSectionTest() {
750 first_type_ = std::get<0>(GetParam());
751 second_type_ = std::get<1>(GetParam());
752 }
753
754 cricket::MediaType first_type_;
755 cricket::MediaType second_type_;
756};
757
Steve Anton5c72e712018-12-10 14:25:30 -0800758// Test that recycling works properly when a new transceiver recycles an m=
759// section that was rejected in both the current local and remote descriptions.
760TEST_P(RecycleMediaSectionTest, CurrentLocalAndCurrentRemoteRejected) {
Steve Antondcc3c022017-12-22 16:02:54 -0800761 auto caller = CreatePeerConnection();
762 auto first_transceiver = caller->AddTransceiver(first_type_);
763 auto callee = CreatePeerConnection();
764
765 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
766
767 std::string first_mid = *first_transceiver->mid();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200768 first_transceiver->StopInternal();
Steve Antondcc3c022017-12-22 16:02:54 -0800769
770 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
771
772 auto second_transceiver = caller->AddTransceiver(second_type_);
773
774 // The offer should reuse the previous media section but allocate a new MID
775 // and change the media type.
776 auto offer = caller->CreateOffer();
777 auto offer_contents = offer->description()->contents();
778 ASSERT_EQ(1u, offer_contents.size());
779 EXPECT_FALSE(offer_contents[0].rejected);
780 EXPECT_EQ(second_type_, offer_contents[0].media_description()->type());
781 std::string second_mid = offer_contents[0].name;
782 EXPECT_NE(first_mid, second_mid);
783
784 // Setting the local offer will dissociate the previous transceiver and set
785 // the MID for the new transceiver.
786 ASSERT_TRUE(
787 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200788 EXPECT_EQ(absl::nullopt, first_transceiver->mid());
Steve Antondcc3c022017-12-22 16:02:54 -0800789 EXPECT_EQ(second_mid, second_transceiver->mid());
790
791 // Setting the remote offer will dissociate the previous transceiver and
792 // create a new transceiver for the media section.
793 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
794 auto callee_transceivers = callee->pc()->GetTransceivers();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200795 ASSERT_EQ(1u, callee_transceivers.size());
796 EXPECT_EQ(second_mid, callee_transceivers[0]->mid());
797 EXPECT_EQ(second_type_, callee_transceivers[0]->media_type());
Steve Antondcc3c022017-12-22 16:02:54 -0800798
799 // The answer should have only one media section for the new transceiver.
800 auto answer = callee->CreateAnswer();
801 auto answer_contents = answer->description()->contents();
802 ASSERT_EQ(1u, answer_contents.size());
803 EXPECT_FALSE(answer_contents[0].rejected);
804 EXPECT_EQ(second_mid, answer_contents[0].name);
805 EXPECT_EQ(second_type_, answer_contents[0].media_description()->type());
806
807 // Setting the local answer should succeed.
808 ASSERT_TRUE(
809 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
810
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800811 // Setting the remote answer should succeed and not create any new
812 // transceivers.
Steve Antondcc3c022017-12-22 16:02:54 -0800813 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
Harald Alvestrand6060df52020-08-11 09:54:02 +0200814 ASSERT_EQ(1u, caller->pc()->GetTransceivers().size());
815 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
Steve Antondcc3c022017-12-22 16:02:54 -0800816}
817
Steve Anton5c72e712018-12-10 14:25:30 -0800818// Test that recycling works properly when a new transceiver recycles an m=
819// section that was rejected in only the current remote description.
820TEST_P(RecycleMediaSectionTest, CurrentRemoteOnlyRejected) {
821 auto caller = CreatePeerConnection();
822 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
823 auto callee = CreatePeerConnection();
824
825 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
826
827 std::string first_mid = *caller_first_transceiver->mid();
828 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
829 auto callee_first_transceiver = callee->pc()->GetTransceivers()[0];
Harald Alvestrand6060df52020-08-11 09:54:02 +0200830 callee_first_transceiver->StopInternal();
Steve Anton5c72e712018-12-10 14:25:30 -0800831
832 // The answer will have a rejected m= section.
833 ASSERT_TRUE(
834 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
835
836 // The offer should reuse the previous media section but allocate a new MID
837 // and change the media type.
838 auto caller_second_transceiver = caller->AddTransceiver(second_type_);
839 auto offer = caller->CreateOffer();
840 const auto& offer_contents = offer->description()->contents();
841 ASSERT_EQ(1u, offer_contents.size());
842 EXPECT_FALSE(offer_contents[0].rejected);
843 EXPECT_EQ(second_type_, offer_contents[0].media_description()->type());
844 std::string second_mid = offer_contents[0].name;
845 EXPECT_NE(first_mid, second_mid);
846
847 // Setting the local offer will dissociate the previous transceiver and set
848 // the MID for the new transceiver.
849 ASSERT_TRUE(
850 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
851 EXPECT_EQ(absl::nullopt, caller_first_transceiver->mid());
852 EXPECT_EQ(second_mid, caller_second_transceiver->mid());
853
854 // Setting the remote offer will dissociate the previous transceiver and
855 // create a new transceiver for the media section.
856 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
857 auto callee_transceivers = callee->pc()->GetTransceivers();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200858 ASSERT_EQ(1u, callee_transceivers.size());
859 EXPECT_EQ(second_mid, callee_transceivers[0]->mid());
860 EXPECT_EQ(second_type_, callee_transceivers[0]->media_type());
Steve Anton5c72e712018-12-10 14:25:30 -0800861
862 // The answer should have only one media section for the new transceiver.
863 auto answer = callee->CreateAnswer();
864 auto answer_contents = answer->description()->contents();
865 ASSERT_EQ(1u, answer_contents.size());
866 EXPECT_FALSE(answer_contents[0].rejected);
867 EXPECT_EQ(second_mid, answer_contents[0].name);
868 EXPECT_EQ(second_type_, answer_contents[0].media_description()->type());
869
870 // Setting the local answer should succeed.
871 ASSERT_TRUE(
872 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
873
874 // Setting the remote answer should succeed and not create any new
875 // transceivers.
876 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
Harald Alvestrand6060df52020-08-11 09:54:02 +0200877 ASSERT_EQ(1u, caller->pc()->GetTransceivers().size());
878 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
Steve Anton5c72e712018-12-10 14:25:30 -0800879}
880
881// Test that recycling works properly when a new transceiver recycles an m=
882// section that was rejected only in the current local description.
883TEST_P(RecycleMediaSectionTest, CurrentLocalOnlyRejected) {
884 auto caller = CreatePeerConnection();
885 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
886 auto callee = CreatePeerConnection();
887
888 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
889
890 std::string first_mid = *caller_first_transceiver->mid();
891 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
892 auto callee_first_transceiver = callee->pc()->GetTransceivers()[0];
Harald Alvestrand6060df52020-08-11 09:54:02 +0200893 callee_first_transceiver->StopInternal();
Steve Anton5c72e712018-12-10 14:25:30 -0800894
895 // The answer will have a rejected m= section.
896 ASSERT_TRUE(
897 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
898
899 // The offer should reuse the previous media section but allocate a new MID
900 // and change the media type.
901 auto callee_second_transceiver = callee->AddTransceiver(second_type_);
902 auto offer = callee->CreateOffer();
903 const auto& offer_contents = offer->description()->contents();
904 ASSERT_EQ(1u, offer_contents.size());
905 EXPECT_FALSE(offer_contents[0].rejected);
906 EXPECT_EQ(second_type_, offer_contents[0].media_description()->type());
907 std::string second_mid = offer_contents[0].name;
908 EXPECT_NE(first_mid, second_mid);
909
910 // Setting the local offer will dissociate the previous transceiver and set
911 // the MID for the new transceiver.
912 ASSERT_TRUE(
913 callee->SetLocalDescription(CloneSessionDescription(offer.get())));
914 EXPECT_EQ(absl::nullopt, callee_first_transceiver->mid());
915 EXPECT_EQ(second_mid, callee_second_transceiver->mid());
916
917 // Setting the remote offer will dissociate the previous transceiver and
918 // create a new transceiver for the media section.
919 ASSERT_TRUE(caller->SetRemoteDescription(std::move(offer)));
920 auto caller_transceivers = caller->pc()->GetTransceivers();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200921 ASSERT_EQ(1u, caller_transceivers.size());
922 EXPECT_EQ(second_mid, caller_transceivers[0]->mid());
923 EXPECT_EQ(second_type_, caller_transceivers[0]->media_type());
Steve Anton5c72e712018-12-10 14:25:30 -0800924
925 // The answer should have only one media section for the new transceiver.
926 auto answer = caller->CreateAnswer();
927 auto answer_contents = answer->description()->contents();
928 ASSERT_EQ(1u, answer_contents.size());
929 EXPECT_FALSE(answer_contents[0].rejected);
930 EXPECT_EQ(second_mid, answer_contents[0].name);
931 EXPECT_EQ(second_type_, answer_contents[0].media_description()->type());
932
933 // Setting the local answer should succeed.
934 ASSERT_TRUE(
935 caller->SetLocalDescription(CloneSessionDescription(answer.get())));
936
937 // Setting the remote answer should succeed and not create any new
938 // transceivers.
939 ASSERT_TRUE(callee->SetRemoteDescription(std::move(answer)));
Harald Alvestrand6060df52020-08-11 09:54:02 +0200940 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
941 ASSERT_EQ(1u, caller->pc()->GetTransceivers().size());
Steve Anton5c72e712018-12-10 14:25:30 -0800942}
943
944// Test that a m= section is *not* recycled if the media section is only
945// rejected in the pending local description and there is no current remote
946// description.
947TEST_P(RecycleMediaSectionTest, PendingLocalRejectedAndNoRemote) {
948 auto caller = CreatePeerConnection();
949 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
950
951 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
952
953 std::string first_mid = *caller_first_transceiver->mid();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200954 caller_first_transceiver->StopInternal();
Steve Anton5c72e712018-12-10 14:25:30 -0800955
956 // The reoffer will have a rejected m= section.
957 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
958
959 auto caller_second_transceiver = caller->AddTransceiver(second_type_);
960
961 // The reoffer should not recycle the existing m= section since it is not
962 // rejected in either the *current* local or *current* remote description.
963 auto reoffer = caller->CreateOffer();
964 auto reoffer_contents = reoffer->description()->contents();
965 ASSERT_EQ(2u, reoffer_contents.size());
966 EXPECT_TRUE(reoffer_contents[0].rejected);
967 EXPECT_EQ(first_type_, reoffer_contents[0].media_description()->type());
968 EXPECT_EQ(first_mid, reoffer_contents[0].name);
969 EXPECT_FALSE(reoffer_contents[1].rejected);
970 EXPECT_EQ(second_type_, reoffer_contents[1].media_description()->type());
971 std::string second_mid = reoffer_contents[1].name;
972 EXPECT_NE(first_mid, second_mid);
973
974 ASSERT_TRUE(caller->SetLocalDescription(std::move(reoffer)));
975
976 // Both RtpTransceivers are associated.
977 EXPECT_EQ(first_mid, caller_first_transceiver->mid());
978 EXPECT_EQ(second_mid, caller_second_transceiver->mid());
979}
980
981// Test that a m= section is *not* recycled if the media section is only
982// rejected in the pending local description and not rejected in the current
983// remote description.
984TEST_P(RecycleMediaSectionTest, PendingLocalRejectedAndNotRejectedRemote) {
985 auto caller = CreatePeerConnection();
986 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
987 auto callee = CreatePeerConnection();
988
989 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
990
991 std::string first_mid = *caller_first_transceiver->mid();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200992 caller_first_transceiver->StopInternal();
Steve Anton5c72e712018-12-10 14:25:30 -0800993
994 // The reoffer will have a rejected m= section.
995 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
996
997 auto caller_second_transceiver = caller->AddTransceiver(second_type_);
998
999 // The reoffer should not recycle the existing m= section since it is not
1000 // rejected in either the *current* local or *current* remote description.
1001 auto reoffer = caller->CreateOffer();
1002 auto reoffer_contents = reoffer->description()->contents();
1003 ASSERT_EQ(2u, reoffer_contents.size());
1004 EXPECT_TRUE(reoffer_contents[0].rejected);
1005 EXPECT_EQ(first_type_, reoffer_contents[0].media_description()->type());
1006 EXPECT_EQ(first_mid, reoffer_contents[0].name);
1007 EXPECT_FALSE(reoffer_contents[1].rejected);
1008 EXPECT_EQ(second_type_, reoffer_contents[1].media_description()->type());
1009 std::string second_mid = reoffer_contents[1].name;
1010 EXPECT_NE(first_mid, second_mid);
1011
1012 ASSERT_TRUE(caller->SetLocalDescription(std::move(reoffer)));
1013
1014 // Both RtpTransceivers are associated.
1015 EXPECT_EQ(first_mid, caller_first_transceiver->mid());
1016 EXPECT_EQ(second_mid, caller_second_transceiver->mid());
1017}
1018
1019// Test that an m= section is *not* recycled if the media section is only
1020// rejected in the pending remote description and there is no current local
1021// description.
1022TEST_P(RecycleMediaSectionTest, PendingRemoteRejectedAndNoLocal) {
1023 auto caller = CreatePeerConnection();
1024 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
1025 auto callee = CreatePeerConnection();
1026
1027 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1028
1029 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
1030 auto callee_first_transceiver = callee->pc()->GetTransceivers()[0];
1031 std::string first_mid = *callee_first_transceiver->mid();
Harald Alvestrand6060df52020-08-11 09:54:02 +02001032 caller_first_transceiver->StopInternal();
Steve Anton5c72e712018-12-10 14:25:30 -08001033
1034 // The reoffer will have a rejected m= section.
1035 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1036
1037 auto callee_second_transceiver = callee->AddTransceiver(second_type_);
1038
1039 // The reoffer should not recycle the existing m= section since it is not
1040 // rejected in either the *current* local or *current* remote description.
1041 auto reoffer = callee->CreateOffer();
1042 auto reoffer_contents = reoffer->description()->contents();
1043 ASSERT_EQ(2u, reoffer_contents.size());
1044 EXPECT_TRUE(reoffer_contents[0].rejected);
1045 EXPECT_EQ(first_type_, reoffer_contents[0].media_description()->type());
1046 EXPECT_EQ(first_mid, reoffer_contents[0].name);
1047 EXPECT_FALSE(reoffer_contents[1].rejected);
1048 EXPECT_EQ(second_type_, reoffer_contents[1].media_description()->type());
1049 std::string second_mid = reoffer_contents[1].name;
1050 EXPECT_NE(first_mid, second_mid);
1051
1052 // Note: Cannot actually set the reoffer since the callee is in the signaling
1053 // state 'have-remote-offer'.
1054}
1055
1056// Test that an m= section is *not* recycled if the media section is only
1057// rejected in the pending remote description and not rejected in the current
1058// local description.
1059TEST_P(RecycleMediaSectionTest, PendingRemoteRejectedAndNotRejectedLocal) {
1060 auto caller = CreatePeerConnection();
1061 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
1062 auto callee = CreatePeerConnection();
1063
1064 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1065
1066 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
1067 auto callee_first_transceiver = callee->pc()->GetTransceivers()[0];
1068 std::string first_mid = *callee_first_transceiver->mid();
Harald Alvestrand6060df52020-08-11 09:54:02 +02001069 caller_first_transceiver->StopInternal();
Steve Anton5c72e712018-12-10 14:25:30 -08001070
1071 // The reoffer will have a rejected m= section.
1072 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1073
1074 auto callee_second_transceiver = callee->AddTransceiver(second_type_);
1075
1076 // The reoffer should not recycle the existing m= section since it is not
1077 // rejected in either the *current* local or *current* remote description.
1078 auto reoffer = callee->CreateOffer();
1079 auto reoffer_contents = reoffer->description()->contents();
1080 ASSERT_EQ(2u, reoffer_contents.size());
1081 EXPECT_TRUE(reoffer_contents[0].rejected);
1082 EXPECT_EQ(first_type_, reoffer_contents[0].media_description()->type());
1083 EXPECT_EQ(first_mid, reoffer_contents[0].name);
1084 EXPECT_FALSE(reoffer_contents[1].rejected);
1085 EXPECT_EQ(second_type_, reoffer_contents[1].media_description()->type());
1086 std::string second_mid = reoffer_contents[1].name;
1087 EXPECT_NE(first_mid, second_mid);
1088
1089 // Note: Cannot actually set the reoffer since the callee is in the signaling
1090 // state 'have-remote-offer'.
1091}
1092
Steve Antondcc3c022017-12-22 16:02:54 -08001093// Test all combinations of audio and video as the first and second media type
1094// for the media section. This is needed for full test coverage because
1095// MediaSession has separate functions for processing audio and video media
1096// sections.
Mirko Bonadeic84f6612019-01-31 12:20:57 +01001097INSTANTIATE_TEST_SUITE_P(
Steve Antondcc3c022017-12-22 16:02:54 -08001098 PeerConnectionJsepTest,
1099 RecycleMediaSectionTest,
1100 Combine(Values(cricket::MEDIA_TYPE_AUDIO, cricket::MEDIA_TYPE_VIDEO),
1101 Values(cricket::MEDIA_TYPE_AUDIO, cricket::MEDIA_TYPE_VIDEO)));
1102
Steve Antonfa2260d2017-12-28 16:38:23 -08001103// Test that a new data channel section will not reuse a recycleable audio or
1104// video media section. Additionally, tests that the new section is added to the
1105// end of the session description.
1106TEST_F(PeerConnectionJsepTest, DataChannelDoesNotRecycleMediaSection) {
1107 auto caller = CreatePeerConnection();
1108 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1109 auto callee = CreatePeerConnection();
1110
1111 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1112
Harald Alvestrand6060df52020-08-11 09:54:02 +02001113 transceiver->StopInternal();
Steve Antonfa2260d2017-12-28 16:38:23 -08001114
1115 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1116
1117 caller->CreateDataChannel("dc");
1118
1119 auto offer = caller->CreateOffer();
1120 auto offer_contents = offer->description()->contents();
1121 ASSERT_EQ(2u, offer_contents.size());
1122 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO,
1123 offer_contents[0].media_description()->type());
1124 EXPECT_EQ(cricket::MEDIA_TYPE_DATA,
1125 offer_contents[1].media_description()->type());
1126
1127 ASSERT_TRUE(
1128 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
1129 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1130
1131 auto answer = callee->CreateAnswer();
1132 auto answer_contents = answer->description()->contents();
1133 ASSERT_EQ(2u, answer_contents.size());
1134 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO,
1135 answer_contents[0].media_description()->type());
1136 EXPECT_EQ(cricket::MEDIA_TYPE_DATA,
1137 answer_contents[1].media_description()->type());
1138}
1139
1140// Test that if a new track is added to an existing session that has a data,
1141// the new section comes at the end of the new offer, after the existing data
1142// section.
1143TEST_F(PeerConnectionJsepTest, AudioTrackAddedAfterDataSectionInReoffer) {
1144 auto caller = CreatePeerConnection();
1145 caller->CreateDataChannel("dc");
1146 auto callee = CreatePeerConnection();
1147
1148 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1149
1150 caller->AddAudioTrack("a");
1151
1152 auto offer = caller->CreateOffer();
1153 auto contents = offer->description()->contents();
1154 ASSERT_EQ(2u, contents.size());
1155 EXPECT_EQ(cricket::MEDIA_TYPE_DATA, contents[0].media_description()->type());
1156 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, contents[1].media_description()->type());
1157}
1158
Steve Antondcc3c022017-12-22 16:02:54 -08001159// Tests for MID properties.
1160
1161static void RenameSection(size_t mline_index,
1162 const std::string& new_mid,
1163 SessionDescriptionInterface* sdesc) {
1164 cricket::SessionDescription* desc = sdesc->description();
1165 std::string old_mid = desc->contents()[mline_index].name;
1166 desc->contents()[mline_index].name = new_mid;
1167 desc->transport_infos()[mline_index].content_name = new_mid;
1168 const cricket::ContentGroup* bundle =
1169 desc->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1170 if (bundle) {
1171 cricket::ContentGroup new_bundle = *bundle;
1172 if (new_bundle.RemoveContentName(old_mid)) {
1173 new_bundle.AddContentName(new_mid);
1174 }
1175 desc->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1176 desc->AddGroup(new_bundle);
1177 }
1178}
1179
1180// Test that two PeerConnections can have a successful offer/answer exchange if
1181// the MIDs are changed from the defaults.
1182TEST_F(PeerConnectionJsepTest, OfferAnswerWithChangedMids) {
1183 constexpr char kFirstMid[] = "nondefaultmid";
1184 constexpr char kSecondMid[] = "randommid";
1185
1186 auto caller = CreatePeerConnection();
1187 caller->AddAudioTrack("a");
1188 caller->AddAudioTrack("b");
1189 auto callee = CreatePeerConnection();
1190
1191 auto offer = caller->CreateOffer();
1192 RenameSection(0, kFirstMid, offer.get());
1193 RenameSection(1, kSecondMid, offer.get());
1194
1195 ASSERT_TRUE(
1196 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
1197 auto caller_transceivers = caller->pc()->GetTransceivers();
1198 EXPECT_EQ(kFirstMid, caller_transceivers[0]->mid());
1199 EXPECT_EQ(kSecondMid, caller_transceivers[1]->mid());
1200
1201 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1202 auto callee_transceivers = callee->pc()->GetTransceivers();
1203 EXPECT_EQ(kFirstMid, callee_transceivers[0]->mid());
1204 EXPECT_EQ(kSecondMid, callee_transceivers[1]->mid());
1205
1206 auto answer = callee->CreateAnswer();
1207 auto answer_contents = answer->description()->contents();
1208 EXPECT_EQ(kFirstMid, answer_contents[0].name);
1209 EXPECT_EQ(kSecondMid, answer_contents[1].name);
1210
1211 ASSERT_TRUE(
1212 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
1213 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
1214}
1215
1216// Test that CreateOffer will generate a MID that is not already used if the
1217// default it would have picked is already taken. This is tested by using a
1218// third PeerConnection to determine what the default would be for the second
1219// media section then setting that as the first media section's MID.
1220TEST_F(PeerConnectionJsepTest, CreateOfferGeneratesUniqueMidIfAlreadyTaken) {
1221 // First, find what the default MID is for the second media section.
1222 auto pc = CreatePeerConnection();
1223 pc->AddAudioTrack("a");
1224 pc->AddAudioTrack("b");
1225 auto default_offer = pc->CreateOffer();
1226 std::string default_second_mid =
1227 default_offer->description()->contents()[1].name;
1228
1229 // Now, do an offer/answer with one track which has the MID set to the default
1230 // second MID.
1231 auto caller = CreatePeerConnection();
1232 caller->AddAudioTrack("a");
1233 auto callee = CreatePeerConnection();
1234
1235 auto offer = caller->CreateOffer();
1236 RenameSection(0, default_second_mid, offer.get());
1237
1238 ASSERT_TRUE(
1239 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
1240 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1241 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1242
1243 // Add a second track and ensure that the MID is different.
1244 caller->AddAudioTrack("b");
1245
1246 auto reoffer = caller->CreateOffer();
1247 auto reoffer_contents = reoffer->description()->contents();
1248 EXPECT_EQ(default_second_mid, reoffer_contents[0].name);
1249 EXPECT_NE(reoffer_contents[0].name, reoffer_contents[1].name);
1250}
1251
Steve Antonfa2260d2017-12-28 16:38:23 -08001252// Test that if an audio or video section has the default data section MID, then
1253// CreateOffer will generate a unique MID for the newly added data section.
1254TEST_F(PeerConnectionJsepTest,
1255 CreateOfferGeneratesUniqueMidForDataSectionIfAlreadyTaken) {
1256 // First, find what the default MID is for the data channel.
1257 auto pc = CreatePeerConnection();
1258 pc->CreateDataChannel("dc");
1259 auto default_offer = pc->CreateOffer();
1260 std::string default_data_mid =
1261 default_offer->description()->contents()[0].name;
1262
1263 // Now do an offer/answer with one audio track which has a MID set to the
1264 // default data MID.
1265 auto caller = CreatePeerConnection();
1266 caller->AddAudioTrack("a");
1267 auto callee = CreatePeerConnection();
1268
1269 auto offer = caller->CreateOffer();
1270 RenameSection(0, default_data_mid, offer.get());
1271
1272 ASSERT_TRUE(
1273 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
1274 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1275 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1276
1277 // Add a data channel and ensure that the MID is different.
1278 caller->CreateDataChannel("dc");
1279
1280 auto reoffer = caller->CreateOffer();
1281 auto reoffer_contents = reoffer->description()->contents();
1282 EXPECT_EQ(default_data_mid, reoffer_contents[0].name);
1283 EXPECT_NE(reoffer_contents[0].name, reoffer_contents[1].name);
1284}
1285
Steve Antondcc3c022017-12-22 16:02:54 -08001286// Test that a reoffer initiated by the callee adds a new track to the caller.
1287TEST_F(PeerConnectionJsepTest, CalleeDoesReoffer) {
1288 auto caller = CreatePeerConnection();
1289 caller->AddAudioTrack("a");
1290 auto callee = CreatePeerConnection();
1291 callee->AddAudioTrack("a");
1292 callee->AddVideoTrack("v");
1293
1294 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1295
1296 EXPECT_EQ(1u, caller->pc()->GetTransceivers().size());
1297 EXPECT_EQ(2u, callee->pc()->GetTransceivers().size());
1298
1299 ASSERT_TRUE(callee->ExchangeOfferAnswerWith(caller.get()));
1300
1301 EXPECT_EQ(2u, caller->pc()->GetTransceivers().size());
1302 EXPECT_EQ(2u, callee->pc()->GetTransceivers().size());
1303}
1304
Steve Anton02ee47c2018-01-10 16:26:06 -08001305// Tests for MSID properties.
1306
1307// Test that adding a track with AddTrack results in an offer that signals the
1308// track's ID.
1309TEST_F(PeerConnectionJsepTest, AddingTrackWithAddTrackSpecifiesTrackId) {
1310 const std::string kTrackId = "audio_track";
1311
1312 auto caller = CreatePeerConnection();
1313 caller->AddAudioTrack(kTrackId);
1314
1315 auto offer = caller->CreateOffer();
1316 auto contents = offer->description()->contents();
1317 ASSERT_EQ(1u, contents.size());
1318 auto streams = contents[0].media_description()->streams();
1319 ASSERT_EQ(1u, streams.size());
1320 EXPECT_EQ(kTrackId, streams[0].id);
1321}
1322
1323// Test that adding a track by calling AddTransceiver then SetTrack results in
1324// an offer that does not signal the track's ID and signals a random ID.
1325TEST_F(PeerConnectionJsepTest,
1326 AddingTrackWithAddTransceiverSpecifiesRandomTrackId) {
1327 const std::string kTrackId = "audio_track";
1328
1329 auto caller = CreatePeerConnection();
1330 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1331 transceiver->sender()->SetTrack(caller->CreateAudioTrack(kTrackId));
1332
1333 auto offer = caller->CreateOffer();
1334 auto contents = offer->description()->contents();
1335 ASSERT_EQ(1u, contents.size());
1336 auto streams = contents[0].media_description()->streams();
1337 ASSERT_EQ(1u, streams.size());
1338 EXPECT_NE(kTrackId, streams[0].id);
1339}
1340
Steve Anton5f94aa22018-02-01 10:58:30 -08001341// Test that if the transceiver is recvonly or inactive, then no MSID
1342// information is included in the offer.
1343TEST_F(PeerConnectionJsepTest, NoMsidInOfferIfTransceiverDirectionHasNoSend) {
1344 auto caller = CreatePeerConnection();
1345
1346 RtpTransceiverInit init_recvonly;
1347 init_recvonly.direction = RtpTransceiverDirection::kRecvOnly;
1348 ASSERT_TRUE(caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init_recvonly));
1349
1350 RtpTransceiverInit init_inactive;
1351 init_inactive.direction = RtpTransceiverDirection::kInactive;
1352 ASSERT_TRUE(caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init_inactive));
1353
1354 auto offer = caller->CreateOffer();
1355 auto contents = offer->description()->contents();
1356 ASSERT_EQ(2u, contents.size());
1357 // MSID is specified in the first stream, so no streams means no MSID.
1358 EXPECT_EQ(0u, contents[0].media_description()->streams().size());
1359 EXPECT_EQ(0u, contents[1].media_description()->streams().size());
1360}
1361
1362// Test that if an answer negotiates transceiver directions of recvonly or
1363// inactive, then no MSID information is included in the answer.
1364TEST_F(PeerConnectionJsepTest, NoMsidInAnswerIfNoRespondingTracks) {
1365 auto caller = CreatePeerConnection();
1366 auto callee = CreatePeerConnection();
1367
1368 // recvonly transceiver will get negotiated to inactive since the callee has
1369 // no tracks to send in response.
1370 RtpTransceiverInit init_recvonly;
1371 init_recvonly.direction = RtpTransceiverDirection::kRecvOnly;
1372 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init_recvonly);
1373
1374 // sendrecv transceiver will get negotiated to recvonly since the callee has
1375 // no tracks to send in response.
1376 RtpTransceiverInit init_sendrecv;
1377 init_sendrecv.direction = RtpTransceiverDirection::kSendRecv;
1378 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init_sendrecv);
1379
1380 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1381
1382 auto answer = callee->CreateAnswer();
1383 auto contents = answer->description()->contents();
1384 ASSERT_EQ(2u, contents.size());
1385 // MSID is specified in the first stream, so no streams means no MSID.
1386 EXPECT_EQ(0u, contents[0].media_description()->streams().size());
1387 EXPECT_EQ(0u, contents[1].media_description()->streams().size());
1388}
1389
1390// Test that the MSID is included even if the transceiver direction has changed
1391// to inactive if the transceiver had previously sent media.
1392TEST_F(PeerConnectionJsepTest, IncludeMsidEvenIfDirectionHasChanged) {
1393 auto caller = CreatePeerConnection();
1394 caller->AddAudioTrack("audio");
1395 auto callee = CreatePeerConnection();
1396 callee->AddAudioTrack("audio");
1397
1398 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1399
Harald Alvestrand6060df52020-08-11 09:54:02 +02001400 caller->pc()->GetTransceivers()[0]->SetDirectionWithError(
Steve Anton5f94aa22018-02-01 10:58:30 -08001401 RtpTransceiverDirection::kInactive);
1402
1403 // The transceiver direction on both sides will turn to inactive.
1404 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1405
1406 auto* offer = callee->pc()->remote_description();
1407 auto offer_contents = offer->description()->contents();
1408 ASSERT_EQ(1u, offer_contents.size());
1409 // MSID is specified in the first stream. If it is present, assume that MSID
1410 // is there.
1411 EXPECT_EQ(1u, offer_contents[0].media_description()->streams().size());
1412
1413 auto* answer = caller->pc()->remote_description();
1414 auto answer_contents = answer->description()->contents();
1415 ASSERT_EQ(1u, answer_contents.size());
1416 EXPECT_EQ(1u, answer_contents[0].media_description()->streams().size());
1417}
1418
1419// Test that stopping a RtpTransceiver will cause future offers to not include
1420// any MSID information for that section.
1421TEST_F(PeerConnectionJsepTest, RemoveMsidIfTransceiverStopped) {
1422 auto caller = CreatePeerConnection();
1423 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1424 auto callee = CreatePeerConnection();
1425
1426 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1427
Harald Alvestrand6060df52020-08-11 09:54:02 +02001428 transceiver->StopInternal();
Steve Anton5f94aa22018-02-01 10:58:30 -08001429
1430 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1431
1432 auto* offer = callee->pc()->remote_description();
1433 auto offer_contents = offer->description()->contents();
1434 ASSERT_EQ(1u, offer_contents.size());
1435 // MSID is specified in the first stream, so no streams means no MSID.
1436 EXPECT_EQ(0u, offer_contents[0].media_description()->streams().size());
1437}
1438
Steve Anton02ee47c2018-01-10 16:26:06 -08001439// Test that the callee RtpReceiver created by a call to SetRemoteDescription
1440// has its ID set to the signaled track ID.
1441TEST_F(PeerConnectionJsepTest,
1442 RtpReceiverCreatedBySetRemoteDescriptionHasSignaledTrackId) {
1443 const std::string kTrackId = "audio_track";
1444
1445 auto caller = CreatePeerConnection();
1446 auto callee = CreatePeerConnection();
1447 caller->AddAudioTrack(kTrackId);
1448
1449 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1450
1451 ASSERT_EQ(1u, callee->pc()->GetReceivers().size());
1452 auto receiver = callee->pc()->GetReceivers()[0];
1453 EXPECT_EQ(kTrackId, receiver->id());
1454}
1455
1456// Test that if the callee RtpReceiver is reused by a call to
1457// SetRemoteDescription, its ID does not change.
1458TEST_F(PeerConnectionJsepTest,
1459 RtpReceiverCreatedBeforeSetRemoteDescriptionKeepsId) {
1460 const std::string kTrackId = "audio_track";
1461
1462 auto caller = CreatePeerConnection();
1463 auto callee = CreatePeerConnection();
1464 caller->AddAudioTrack(kTrackId);
1465 callee->AddAudioTrack("dummy_track");
1466
1467 ASSERT_EQ(1u, callee->pc()->GetReceivers().size());
1468 auto receiver = callee->pc()->GetReceivers()[0];
1469 std::string receiver_id = receiver->id();
1470
1471 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1472
1473 EXPECT_EQ(receiver_id, receiver->id());
1474}
1475
Steve Antonef65ef12018-01-10 17:15:20 -08001476// Test that setting a remote offer with one track that has no streams fires off
1477// the correct OnAddTrack event.
1478TEST_F(PeerConnectionJsepTest,
1479 SetRemoteOfferWithOneTrackNoStreamFiresOnAddTrack) {
1480 const std::string kTrackLabel = "audio_track";
1481
1482 auto caller = CreatePeerConnection();
1483 auto callee = CreatePeerConnection();
1484 ASSERT_TRUE(caller->AddAudioTrack(kTrackLabel));
1485
1486 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1487
Seth Hampson5b4f0752018-04-02 16:31:36 -07001488 const auto& track_events = callee->observer()->add_track_events_;
1489 ASSERT_EQ(1u, track_events.size());
1490 const auto& event = track_events[0];
1491 EXPECT_EQ(kTrackLabel, event.receiver->track()->id());
1492 EXPECT_EQ(0u, event.streams.size());
Steve Antonef65ef12018-01-10 17:15:20 -08001493}
1494
1495// Test that setting a remote offer with one track that has one stream fires off
1496// the correct OnAddTrack event.
1497TEST_F(PeerConnectionJsepTest,
1498 SetRemoteOfferWithOneTrackOneStreamFiresOnAddTrack) {
1499 const std::string kTrackLabel = "audio_track";
Seth Hampson845e8782018-03-02 11:34:10 -08001500 const std::string kStreamId = "audio_stream";
Steve Antonef65ef12018-01-10 17:15:20 -08001501
1502 auto caller = CreatePeerConnection();
1503 auto callee = CreatePeerConnection();
Seth Hampson845e8782018-03-02 11:34:10 -08001504 ASSERT_TRUE(caller->AddAudioTrack(kTrackLabel, {kStreamId}));
Steve Antonef65ef12018-01-10 17:15:20 -08001505
1506 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1507
1508 const auto& track_events = callee->observer()->add_track_events_;
1509 ASSERT_EQ(1u, track_events.size());
1510 const auto& event = track_events[0];
1511 ASSERT_EQ(1u, event.streams.size());
1512 auto stream = event.streams[0];
Seth Hampson13b8bad2018-03-13 16:05:28 -07001513 EXPECT_EQ(kStreamId, stream->id());
Steve Antonef65ef12018-01-10 17:15:20 -08001514 EXPECT_THAT(track_events[0].snapshotted_stream_tracks.at(stream),
1515 ElementsAre(event.receiver->track()));
1516 EXPECT_EQ(event.receiver->streams(), track_events[0].streams);
1517}
1518
1519// Test that setting a remote offer with two tracks that share the same stream
1520// fires off two OnAddTrack events, both with the same stream that has both
1521// tracks present at the time of firing. This is to ensure that track events are
1522// not fired until SetRemoteDescription has finished processing all the media
1523// sections.
1524TEST_F(PeerConnectionJsepTest,
1525 SetRemoteOfferWithTwoTracksSameStreamFiresOnAddTrack) {
1526 const std::string kTrack1Label = "audio_track1";
1527 const std::string kTrack2Label = "audio_track2";
Seth Hampson845e8782018-03-02 11:34:10 -08001528 const std::string kSharedStreamId = "stream";
Steve Antonef65ef12018-01-10 17:15:20 -08001529
1530 auto caller = CreatePeerConnection();
1531 auto callee = CreatePeerConnection();
Seth Hampson845e8782018-03-02 11:34:10 -08001532 ASSERT_TRUE(caller->AddAudioTrack(kTrack1Label, {kSharedStreamId}));
1533 ASSERT_TRUE(caller->AddAudioTrack(kTrack2Label, {kSharedStreamId}));
Steve Antonef65ef12018-01-10 17:15:20 -08001534
1535 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1536
1537 const auto& track_events = callee->observer()->add_track_events_;
1538 ASSERT_EQ(2u, track_events.size());
1539 const auto& event1 = track_events[0];
1540 const auto& event2 = track_events[1];
1541 ASSERT_EQ(1u, event1.streams.size());
1542 auto stream = event1.streams[0];
1543 ASSERT_THAT(event2.streams, ElementsAre(stream));
1544 auto track1 = event1.receiver->track();
1545 auto track2 = event2.receiver->track();
1546 EXPECT_THAT(event1.snapshotted_stream_tracks.at(stream),
1547 UnorderedElementsAre(track1, track2));
1548 EXPECT_THAT(event2.snapshotted_stream_tracks.at(stream),
1549 UnorderedElementsAre(track1, track2));
1550}
1551
Seth Hampson5b4f0752018-04-02 16:31:36 -07001552// Test that setting a remote offer with one track that has two streams fires
1553// off the correct OnAddTrack event.
1554TEST_F(PeerConnectionJsepTest,
1555 SetRemoteOfferWithOneTrackTwoStreamFiresOnAddTrack) {
1556 const std::string kTrackLabel = "audio_track";
1557 const std::string kStreamId1 = "audio_stream1";
1558 const std::string kStreamId2 = "audio_stream2";
1559
1560 auto caller = CreatePeerConnection();
1561 auto callee = CreatePeerConnection();
1562 ASSERT_TRUE(caller->AddAudioTrack(kTrackLabel, {kStreamId1, kStreamId2}));
1563
1564 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1565
1566 const auto& track_events = callee->observer()->add_track_events_;
1567 ASSERT_EQ(1u, track_events.size());
1568 const auto& event = track_events[0];
1569 ASSERT_EQ(2u, event.streams.size());
1570 EXPECT_EQ(kStreamId1, event.streams[0]->id());
1571 EXPECT_EQ(kStreamId2, event.streams[1]->id());
1572}
Steve Antonef65ef12018-01-10 17:15:20 -08001573
Steve Anton54b84072018-02-20 15:19:52 -08001574// Test that if an RtpTransceiver with a current_direction set is stopped, then
1575// current_direction is changed to null.
1576TEST_F(PeerConnectionJsepTest, CurrentDirectionResetWhenRtpTransceiverStopped) {
1577 auto caller = CreatePeerConnection();
1578 auto callee = CreatePeerConnection();
1579
1580 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1581
1582 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1583
1584 ASSERT_TRUE(transceiver->current_direction());
Harald Alvestrand6060df52020-08-11 09:54:02 +02001585 transceiver->StopInternal();
1586 EXPECT_EQ(transceiver->current_direction(),
1587 RtpTransceiverDirection::kStopped);
Steve Anton54b84072018-02-20 15:19:52 -08001588}
1589
Steve Antonba42e992018-04-09 14:10:01 -07001590// Test that you can't set an answer on a PeerConnection before setting the
1591// offer.
Harald Alvestrand5081c0c2018-03-09 15:18:03 +01001592TEST_F(PeerConnectionJsepTest, AnswerBeforeOfferFails) {
1593 auto caller = CreatePeerConnection();
1594 auto callee = CreatePeerConnection();
Harald Alvestrand5081c0c2018-03-09 15:18:03 +01001595 caller->AddAudioTrack("audio");
Steve Antonba42e992018-04-09 14:10:01 -07001596
1597 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1598
1599 RTCError error;
1600 ASSERT_FALSE(caller->SetRemoteDescription(callee->CreateAnswer(), &error));
1601 EXPECT_EQ(RTCErrorType::INVALID_STATE, error.type());
1602}
1603
1604// Test that a Unified Plan PeerConnection fails to set a Plan B offer if it has
1605// two video tracks.
1606TEST_F(PeerConnectionJsepTest, TwoVideoPlanBToUnifiedPlanFails) {
1607 RTCConfiguration config_planb;
1608 config_planb.sdp_semantics = SdpSemantics::kPlanB;
1609 auto caller = CreatePeerConnection(config_planb);
1610 auto callee = CreatePeerConnection();
1611 caller->AddVideoTrack("video1");
1612 caller->AddVideoTrack("video2");
1613
1614 RTCError error;
1615 ASSERT_FALSE(callee->SetRemoteDescription(caller->CreateOffer(), &error));
1616 EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, error.type());
1617}
1618
1619// Test that a Unified Plan PeerConnection fails to set a Plan B answer if it
1620// has two video tracks.
1621TEST_F(PeerConnectionJsepTest, OneVideoUnifiedPlanToTwoVideoPlanBFails) {
1622 auto caller = CreatePeerConnection();
1623 RTCConfiguration config_planb;
1624 config_planb.sdp_semantics = SdpSemantics::kPlanB;
1625 auto callee = CreatePeerConnection(config_planb);
1626 caller->AddVideoTrack("video");
1627 callee->AddVideoTrack("video1");
1628 callee->AddVideoTrack("video2");
1629
1630 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1631
1632 RTCError error;
1633 ASSERT_FALSE(caller->SetRemoteDescription(caller->CreateAnswer(), &error));
1634 EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, error.type());
Harald Alvestrand5081c0c2018-03-09 15:18:03 +01001635}
1636
Steve Anton06817cd2018-12-18 15:55:30 -08001637// Removes the RTP header extension associated with the given URI from the media
1638// description.
1639static void RemoveRtpHeaderExtensionByUri(
1640 MediaContentDescription* media_description,
1641 absl::string_view uri) {
1642 std::vector<RtpExtension> header_extensions =
1643 media_description->rtp_header_extensions();
1644 header_extensions.erase(std::remove_if(
1645 header_extensions.begin(), header_extensions.end(),
1646 [uri](const RtpExtension& extension) { return extension.uri == uri; }));
1647 media_description->set_rtp_header_extensions(header_extensions);
1648}
1649
1650// Transforms a session description to emulate a legacy endpoint which does not
1651// support a=mid, BUNDLE, and the MID header extension.
1652static void ClearMids(SessionDescriptionInterface* sdesc) {
1653 cricket::SessionDescription* desc = sdesc->description();
1654 desc->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1655 cricket::ContentInfo* audio_content = cricket::GetFirstAudioContent(desc);
1656 if (audio_content) {
1657 desc->GetTransportInfoByName(audio_content->name)->content_name = "";
1658 audio_content->name = "";
1659 RemoveRtpHeaderExtensionByUri(audio_content->media_description(),
1660 RtpExtension::kMidUri);
1661 }
1662 cricket::ContentInfo* video_content = cricket::GetFirstVideoContent(desc);
1663 if (video_content) {
1664 desc->GetTransportInfoByName(video_content->name)->content_name = "";
1665 video_content->name = "";
1666 RemoveRtpHeaderExtensionByUri(video_content->media_description(),
1667 RtpExtension::kMidUri);
1668 }
1669}
1670
1671// Test that negotiation works with legacy endpoints which do not support a=mid.
1672TEST_F(PeerConnectionJsepTest, LegacyNoMidAudioOnlyOffer) {
1673 auto caller = CreatePeerConnection();
1674 caller->AddAudioTrack("audio");
1675 auto callee = CreatePeerConnection();
1676 callee->AddAudioTrack("audio");
1677
1678 auto offer = caller->CreateOffer();
1679 ClearMids(offer.get());
1680
1681 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1682 EXPECT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1683}
1684TEST_F(PeerConnectionJsepTest, LegacyNoMidAudioVideoOffer) {
1685 auto caller = CreatePeerConnection();
1686 caller->AddAudioTrack("audio");
1687 caller->AddVideoTrack("video");
1688 auto callee = CreatePeerConnection();
1689 callee->AddAudioTrack("audio");
1690 callee->AddVideoTrack("video");
1691
1692 auto offer = caller->CreateOffer();
1693 ClearMids(offer.get());
1694
1695 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1696 EXPECT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1697}
1698TEST_F(PeerConnectionJsepTest, LegacyNoMidAudioOnlyAnswer) {
1699 auto caller = CreatePeerConnection();
1700 caller->AddAudioTrack("audio");
1701 auto callee = CreatePeerConnection();
1702 callee->AddAudioTrack("audio");
1703
1704 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1705
1706 auto answer = callee->CreateAnswer();
1707 ClearMids(answer.get());
1708
1709 EXPECT_TRUE(caller->SetRemoteDescription(std::move(answer)));
1710}
1711TEST_F(PeerConnectionJsepTest, LegacyNoMidAudioVideoAnswer) {
1712 auto caller = CreatePeerConnection();
1713 caller->AddAudioTrack("audio");
1714 caller->AddVideoTrack("video");
1715 auto callee = CreatePeerConnection();
1716 callee->AddAudioTrack("audio");
1717 callee->AddVideoTrack("video");
1718
1719 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1720
1721 auto answer = callee->CreateAnswer();
1722 ClearMids(answer.get());
1723
1724 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
1725}
1726
Steve Antond7180cc2019-02-07 10:44:53 -08001727// Test that negotiation works with legacy endpoints which do not support a=mid
1728// when setting two remote descriptions without setting a local description in
1729// between.
1730TEST_F(PeerConnectionJsepTest, LegacyNoMidTwoRemoteOffers) {
1731 auto caller = CreatePeerConnection();
1732 caller->AddAudioTrack("audio");
1733 auto callee = CreatePeerConnection();
1734 callee->AddAudioTrack("audio");
1735
1736 auto offer = caller->CreateOffer();
1737 ClearMids(offer.get());
1738
1739 ASSERT_TRUE(
1740 callee->SetRemoteDescription(CloneSessionDescription(offer.get())));
1741 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1742 EXPECT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1743}
1744
Steve Antonceac0152018-12-19 11:32:20 -08001745// Test that SetLocalDescription fails if a=mid lines are missing.
1746TEST_F(PeerConnectionJsepTest, SetLocalDescriptionFailsMissingMid) {
1747 auto caller = CreatePeerConnection();
1748 caller->AddAudioTrack("audio");
1749
1750 auto offer = caller->CreateOffer();
1751 ClearMids(offer.get());
1752
1753 std::string error;
1754 ASSERT_FALSE(caller->SetLocalDescription(std::move(offer), &error));
1755 EXPECT_EQ(
1756 "Failed to set local offer sdp: A media section is missing a MID "
1757 "attribute.",
1758 error);
1759}
1760
Eldar Rello5ab79e62019-10-09 18:29:44 +03001761TEST_F(PeerConnectionJsepTest, RollbackSupportedInUnifiedPlan) {
1762 RTCConfiguration config;
1763 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
1764 config.enable_implicit_rollback = true;
1765 auto caller = CreatePeerConnection(config);
1766 auto callee = CreatePeerConnection(config);
1767 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
1768 EXPECT_TRUE(caller->SetLocalDescription(caller->CreateRollback()));
1769 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
1770 EXPECT_TRUE(caller->SetRemoteDescription(caller->CreateRollback()));
1771 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
1772 EXPECT_TRUE(caller->SetRemoteDescription(callee->CreateOffer()));
1773}
1774
1775TEST_F(PeerConnectionJsepTest, RollbackNotSupportedInPlanB) {
1776 RTCConfiguration config;
1777 config.sdp_semantics = SdpSemantics::kPlanB;
1778 config.enable_implicit_rollback = true;
1779 auto caller = CreatePeerConnection(config);
1780 auto callee = CreatePeerConnection(config);
1781 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
1782 EXPECT_FALSE(caller->SetLocalDescription(caller->CreateRollback()));
1783 EXPECT_FALSE(caller->SetRemoteDescription(caller->CreateRollback()));
1784 EXPECT_FALSE(caller->SetRemoteDescription(callee->CreateOffer()));
1785}
1786
1787TEST_F(PeerConnectionJsepTest, RollbackFailsInStableState) {
1788 auto caller = CreatePeerConnection();
1789 EXPECT_FALSE(caller->SetLocalDescription(caller->CreateRollback()));
1790 EXPECT_FALSE(caller->SetRemoteDescription(caller->CreateRollback()));
1791}
1792
1793TEST_F(PeerConnectionJsepTest, RollbackToStableStateAndClearLocalOffer) {
1794 auto caller = CreatePeerConnection();
1795 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
1796 EXPECT_TRUE(caller->SetLocalDescription(caller->CreateRollback()));
1797 EXPECT_EQ(caller->signaling_state(), PeerConnectionInterface::kStable);
1798 EXPECT_EQ(caller->pc()->pending_local_description(), nullptr);
1799
1800 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
1801 EXPECT_TRUE(caller->SetRemoteDescription(caller->CreateRollback()));
1802 EXPECT_EQ(caller->signaling_state(), PeerConnectionInterface::kStable);
1803 EXPECT_EQ(caller->pc()->pending_local_description(), nullptr);
1804}
1805
1806TEST_F(PeerConnectionJsepTest, RollbackToStableStateAndClearRemoteOffer) {
1807 auto caller = CreatePeerConnection();
1808 auto callee = CreatePeerConnection();
1809 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1810 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
1811 EXPECT_EQ(callee->signaling_state(), PeerConnectionInterface::kStable);
1812 EXPECT_EQ(callee->pc()->pending_remote_description(), nullptr);
1813
1814 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1815 EXPECT_TRUE(callee->SetLocalDescription(caller->CreateRollback()));
1816 EXPECT_EQ(callee->signaling_state(), PeerConnectionInterface::kStable);
1817 EXPECT_EQ(callee->pc()->pending_remote_description(), nullptr);
1818}
1819
Eldar Relloead0ec92019-10-21 23:01:31 +03001820TEST_F(PeerConnectionJsepTest, RollbackImplicitly) {
Eldar Rello5ab79e62019-10-09 18:29:44 +03001821 RTCConfiguration config;
1822 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
1823 config.enable_implicit_rollback = true;
1824 auto caller = CreatePeerConnection(config);
1825 auto callee = CreatePeerConnection(config);
1826 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
1827 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1828 EXPECT_EQ(callee->signaling_state(),
1829 PeerConnectionInterface::kHaveRemoteOffer);
Eldar Relloead0ec92019-10-21 23:01:31 +03001830 EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal());
Henrik Boströme574a312020-08-25 10:20:11 +02001831 EXPECT_FALSE(callee->observer()->legacy_renegotiation_needed());
1832 EXPECT_FALSE(callee->observer()->has_negotiation_needed_event());
Eldar Rello5ab79e62019-10-09 18:29:44 +03001833}
1834
Eldar Relloead0ec92019-10-21 23:01:31 +03001835TEST_F(PeerConnectionJsepTest, RollbackImplicitlyNegotatiationNotNeeded) {
1836 RTCConfiguration config;
1837 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
1838 config.enable_implicit_rollback = true;
1839 auto caller = CreatePeerConnection(config);
1840 auto callee = CreatePeerConnection(config);
1841 caller->AddAudioTrack("a");
1842 callee->AddAudioTrack("b");
1843 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
Henrik Boströme574a312020-08-25 10:20:11 +02001844 callee->observer()->clear_legacy_renegotiation_needed();
1845 callee->observer()->clear_latest_negotiation_needed_event();
Eldar Relloead0ec92019-10-21 23:01:31 +03001846 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1847 EXPECT_EQ(callee->signaling_state(),
1848 PeerConnectionInterface::kHaveRemoteOffer);
1849 EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal());
1850 // No negotiation needed as track got attached in the answer.
Henrik Boströme574a312020-08-25 10:20:11 +02001851 EXPECT_FALSE(callee->observer()->legacy_renegotiation_needed());
1852 EXPECT_FALSE(callee->observer()->has_negotiation_needed_event());
Eldar Relloead0ec92019-10-21 23:01:31 +03001853 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 0u);
1854}
1855
1856TEST_F(PeerConnectionJsepTest, RollbackImplicitlyAndNegotiationNeeded) {
1857 RTCConfiguration config;
1858 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
1859 config.enable_implicit_rollback = true;
1860 auto caller = CreatePeerConnection(config);
1861 auto callee = CreatePeerConnection(config);
1862 callee->AddAudioTrack("a");
1863 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
Henrik Boströme574a312020-08-25 10:20:11 +02001864 callee->observer()->clear_legacy_renegotiation_needed();
1865 callee->observer()->clear_latest_negotiation_needed_event();
Eldar Relloead0ec92019-10-21 23:01:31 +03001866 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1867 EXPECT_EQ(callee->signaling_state(),
1868 PeerConnectionInterface::kHaveRemoteOffer);
Henrik Boströme574a312020-08-25 10:20:11 +02001869 EXPECT_FALSE(callee->observer()->legacy_renegotiation_needed());
1870 EXPECT_FALSE(callee->observer()->has_negotiation_needed_event());
Eldar Relloead0ec92019-10-21 23:01:31 +03001871 EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal());
Henrik Boströme574a312020-08-25 10:20:11 +02001872 EXPECT_TRUE(callee->observer()->legacy_renegotiation_needed());
1873 EXPECT_TRUE(callee->observer()->has_negotiation_needed_event());
Eldar Relloead0ec92019-10-21 23:01:31 +03001874 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 0u);
1875}
1876
1877TEST_F(PeerConnectionJsepTest, AttemptToRollbackImplicitly) {
Eldar Rello5ab79e62019-10-09 18:29:44 +03001878 RTCConfiguration config;
1879 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
1880 config.enable_implicit_rollback = true;
1881 auto caller = CreatePeerConnection(config);
1882 auto callee = CreatePeerConnection(config);
1883 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
1884 EXPECT_FALSE(callee->SetRemoteDescription(
1885 CreateSessionDescription(SdpType::kOffer, "invalid sdp")));
1886 EXPECT_EQ(callee->signaling_state(),
1887 PeerConnectionInterface::kHaveLocalOffer);
1888}
1889
1890TEST_F(PeerConnectionJsepTest, RollbackRemovesTransceiver) {
1891 auto caller = CreatePeerConnection();
1892 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1893 auto callee = CreatePeerConnection();
1894 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
Eldar Relloead0ec92019-10-21 23:01:31 +03001895 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
Eldar Rello5ab79e62019-10-09 18:29:44 +03001896 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
Eldar Relloead0ec92019-10-21 23:01:31 +03001897 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 0u);
1898 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 1u);
Eldar Rello5ab79e62019-10-09 18:29:44 +03001899}
1900
1901TEST_F(PeerConnectionJsepTest, RollbackKeepsTransceiverAndClearsMid) {
1902 auto caller = CreatePeerConnection();
1903 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1904 auto callee = CreatePeerConnection();
1905 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1906 callee->AddAudioTrack("a");
Eldar Relloead0ec92019-10-21 23:01:31 +03001907 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
Eldar Rello5ab79e62019-10-09 18:29:44 +03001908 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
1909 // Transceiver can't be removed as track was added to it.
Eldar Relloead0ec92019-10-21 23:01:31 +03001910 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
Eldar Rello5ab79e62019-10-09 18:29:44 +03001911 // Mid got cleared to make it reusable.
1912 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), absl::nullopt);
1913 // Transceiver should be counted as addTrack-created after rollback.
1914 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
Eldar Relloead0ec92019-10-21 23:01:31 +03001915 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
1916 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 1u);
Eldar Rello5ab79e62019-10-09 18:29:44 +03001917}
1918
Eldar Rello353a7182019-11-25 18:49:44 +02001919TEST_F(PeerConnectionJsepTest,
1920 RollbackKeepsTransceiverAfterAddTrackEvenWhenTrackIsNulled) {
1921 auto caller = CreatePeerConnection();
1922 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1923 auto callee = CreatePeerConnection();
1924 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1925 callee->AddAudioTrack("a");
1926 callee->pc()->GetTransceivers()[0]->sender()->SetTrack(nullptr);
1927 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->sender()->track(), nullptr);
1928 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
1929 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
1930 // Transceiver can't be removed as track was added to it.
1931 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
1932 // Mid got cleared to make it reusable.
1933 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), absl::nullopt);
1934 // Transceiver should be counted as addTrack-created after rollback.
1935 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1936 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
1937 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 1u);
1938}
1939
Eldar Rello5ab79e62019-10-09 18:29:44 +03001940TEST_F(PeerConnectionJsepTest, RollbackRestoresMid) {
1941 auto caller = CreatePeerConnection();
1942 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1943 auto callee = CreatePeerConnection();
1944 callee->AddAudioTrack("a");
1945 auto offer = callee->CreateOffer();
1946 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
Eldar Relloead0ec92019-10-21 23:01:31 +03001947 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
Eldar Rello5ab79e62019-10-09 18:29:44 +03001948 EXPECT_NE(callee->pc()->GetTransceivers()[0]->mid(), absl::nullopt);
1949 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
1950 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), absl::nullopt);
1951 EXPECT_TRUE(callee->SetLocalDescription(std::move(offer)));
1952}
1953
Eldar Rello950d6b92021-04-06 22:38:00 +03001954TEST_F(PeerConnectionJsepTest, RollbackRestoresInitSendEncodings) {
1955 auto caller = CreatePeerConnection();
1956 RtpTransceiverInit init;
1957 init.direction = RtpTransceiverDirection::kSendRecv;
1958 RtpEncodingParameters encoding;
1959 encoding.rid = "hi";
1960 init.send_encodings.push_back(encoding);
1961 encoding.rid = "mid";
1962 init.send_encodings.push_back(encoding);
1963 encoding.rid = "lo";
1964 init.send_encodings.push_back(encoding);
1965 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init);
1966 auto encodings =
1967 caller->pc()->GetTransceivers()[0]->sender()->init_send_encodings();
1968 EXPECT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
1969 EXPECT_NE(caller->pc()->GetTransceivers()[0]->sender()->init_send_encodings(),
1970 encodings);
1971 EXPECT_TRUE(caller->SetLocalDescription(caller->CreateRollback()));
1972 EXPECT_EQ(caller->pc()->GetTransceivers()[0]->sender()->init_send_encodings(),
1973 encodings);
1974}
1975
1976TEST_F(PeerConnectionJsepTest, RollbackDoesNotAffectSendEncodings) {
1977 auto caller = CreatePeerConnection();
1978 auto callee = CreatePeerConnection();
1979 RtpTransceiverInit init;
1980 init.direction = RtpTransceiverDirection::kSendOnly;
1981 RtpEncodingParameters encoding;
1982 encoding.rid = "hi";
1983 init.send_encodings.push_back(encoding);
1984 encoding.rid = "mid";
1985 init.send_encodings.push_back(encoding);
1986 encoding.rid = "lo";
1987 init.send_encodings.push_back(encoding);
1988 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init);
1989 callee->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
1990 callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal());
1991 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal());
1992 auto params = caller->pc()->GetTransceivers()[0]->sender()->GetParameters();
1993 EXPECT_TRUE(params.encodings[0].active);
1994 params.encodings[0].active = false;
1995 caller->pc()->GetTransceivers()[0]->sender()->SetParameters(params);
1996 auto offer = caller->CreateOffer();
1997 std::string offer_string;
1998 EXPECT_TRUE(offer.get()->ToString(&offer_string));
1999 std::string simulcast_line =
2000 offer_string.substr(offer_string.find("a=simulcast"));
2001 EXPECT_FALSE(simulcast_line.empty());
2002 EXPECT_TRUE(caller->SetLocalDescription(std::move(offer)));
2003 EXPECT_TRUE(caller->SetLocalDescription(caller->CreateRollback()));
2004 EXPECT_FALSE(caller->pc()
2005 ->GetTransceivers()[0]
2006 ->sender()
2007 ->GetParameters()
2008 .encodings[0]
2009 .active);
2010 offer = caller->CreateOffer();
2011 EXPECT_TRUE(offer.get()->ToString(&offer_string));
2012 EXPECT_EQ(offer_string.substr(offer_string.find("a=simulcast")),
2013 simulcast_line);
2014}
2015
Eldar Rello5ab79e62019-10-09 18:29:44 +03002016TEST_F(PeerConnectionJsepTest, RollbackRestoresMidAndRemovesTransceiver) {
2017 auto callee = CreatePeerConnection();
2018 callee->AddVideoTrack("a");
2019 auto offer = callee->CreateOffer();
2020 auto caller = CreatePeerConnection();
2021 caller->AddAudioTrack("b");
2022 caller->AddVideoTrack("c");
2023 auto mid = callee->pc()->GetTransceivers()[0]->mid();
2024 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
Eldar Relloead0ec92019-10-21 23:01:31 +03002025 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 2u);
Eldar Rello5ab79e62019-10-09 18:29:44 +03002026 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
Eldar Relloead0ec92019-10-21 23:01:31 +03002027 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
Eldar Rello5ab79e62019-10-09 18:29:44 +03002028 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), mid);
2029 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->media_type(),
2030 cricket::MEDIA_TYPE_VIDEO);
2031 EXPECT_TRUE(callee->SetLocalDescription(std::move(offer)));
Eldar Relloead0ec92019-10-21 23:01:31 +03002032 EXPECT_EQ(callee->observer()->remove_track_events_.size(),
2033 callee->observer()->add_track_events_.size());
2034}
2035
2036TEST_F(PeerConnectionJsepTest, RollbackHasNoEffectOnStableTransceivers) {
2037 auto callee = CreatePeerConnection();
2038 callee->AddVideoTrack("a");
2039 auto caller = CreatePeerConnection();
2040 caller->AddAudioTrack("b");
2041 caller->AddVideoTrack("c");
2042 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2043 EXPECT_TRUE(
2044 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
2045 // In stable don't add or remove anything.
Henrik Boströme574a312020-08-25 10:20:11 +02002046 callee->observer()->clear_legacy_renegotiation_needed();
2047 callee->observer()->clear_latest_negotiation_needed_event();
Eldar Relloead0ec92019-10-21 23:01:31 +03002048 size_t transceiver_count = callee->pc()->GetTransceivers().size();
2049 auto mid_0 = callee->pc()->GetTransceivers()[0]->mid();
2050 auto mid_1 = callee->pc()->GetTransceivers()[1]->mid();
2051 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2052 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
2053 EXPECT_EQ(callee->pc()->GetTransceivers().size(), transceiver_count);
2054 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), mid_0);
2055 EXPECT_EQ(callee->pc()->GetTransceivers()[1]->mid(), mid_1);
2056 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 0u);
Henrik Boströme574a312020-08-25 10:20:11 +02002057 EXPECT_FALSE(callee->observer()->legacy_renegotiation_needed());
2058 EXPECT_FALSE(callee->observer()->has_negotiation_needed_event());
Eldar Rello5ab79e62019-10-09 18:29:44 +03002059}
2060
2061TEST_F(PeerConnectionJsepTest, ImplicitlyRollbackTransceiversWithSameMids) {
2062 RTCConfiguration config;
2063 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
2064 config.enable_implicit_rollback = true;
2065 auto caller = CreatePeerConnection(config);
2066 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2067 auto callee = CreatePeerConnection(config);
2068 callee->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2069 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2070 auto initial_mid = callee->pc()->GetTransceivers()[0]->mid();
2071 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
Eldar Relloead0ec92019-10-21 23:01:31 +03002072 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 2u);
Eldar Rello5ab79e62019-10-09 18:29:44 +03002073 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), absl::nullopt);
2074 EXPECT_EQ(callee->pc()->GetTransceivers()[1]->mid(),
2075 caller->pc()->GetTransceivers()[0]->mid());
2076 EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal()); // Go to stable.
2077 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2078 EXPECT_NE(callee->pc()->GetTransceivers()[0]->mid(), initial_mid);
2079}
2080
2081TEST_F(PeerConnectionJsepTest, RollbackToNegotiatedStableState) {
2082 RTCConfiguration config;
2083 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
2084 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
2085 auto caller = CreatePeerConnection(config);
2086 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
2087 auto callee = CreatePeerConnection(config);
2088 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2089 EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal());
2090 caller->AddVideoTrack("a");
2091 callee->AddVideoTrack("b");
2092 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
Eldar Relloead0ec92019-10-21 23:01:31 +03002093 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 2u);
Eldar Rello5ab79e62019-10-09 18:29:44 +03002094 auto audio_transport =
2095 callee->pc()->GetTransceivers()[0]->sender()->dtls_transport();
2096 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
2097 callee->pc()->GetTransceivers()[1]->sender()->dtls_transport());
2098 EXPECT_NE(callee->pc()->GetTransceivers()[1]->sender()->dtls_transport(),
2099 nullptr);
2100 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
2101 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
2102 audio_transport); // Audio must remain working after rollback.
2103 EXPECT_EQ(callee->pc()->GetTransceivers()[1]->sender()->dtls_transport(),
2104 nullptr);
2105 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2106
2107 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
2108 audio_transport); // Audio transport is still the same.
2109}
2110
Eldar Rello353a7182019-11-25 18:49:44 +02002111TEST_F(PeerConnectionJsepTest, RollbackHasToDestroyTransport) {
2112 RTCConfiguration config;
2113 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
2114 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
2115 auto pc = CreatePeerConnection(config);
2116 pc->AddAudioTrack("a");
2117 pc->AddVideoTrack("b");
2118 EXPECT_TRUE(pc->CreateOfferAndSetAsLocal());
2119 auto offer = pc->CreateOffer();
2120 EXPECT_EQ(pc->pc()->GetTransceivers().size(), 2u);
2121 auto audio_transport =
2122 pc->pc()->GetTransceivers()[0]->sender()->dtls_transport();
2123 EXPECT_EQ(pc->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
2124 pc->pc()->GetTransceivers()[1]->sender()->dtls_transport());
2125 EXPECT_NE(pc->pc()->GetTransceivers()[1]->sender()->dtls_transport(),
2126 nullptr);
2127 EXPECT_TRUE(pc->SetRemoteDescription(pc->CreateRollback()));
2128 EXPECT_TRUE(pc->SetLocalDescription(std::move(offer)));
2129 EXPECT_NE(pc->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
2130 nullptr);
2131 EXPECT_NE(pc->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
2132 audio_transport);
2133}
2134
Eldar Relloead0ec92019-10-21 23:01:31 +03002135TEST_F(PeerConnectionJsepTest, RollbackLocalDirectionChange) {
2136 auto caller = CreatePeerConnection();
2137 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
2138 auto callee = CreatePeerConnection();
2139 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2140 EXPECT_TRUE(
2141 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
2142 callee->AddAudioTrack("a");
Harald Alvestrand6060df52020-08-11 09:54:02 +02002143 callee->pc()->GetTransceivers()[0]->SetDirectionWithError(
Eldar Relloead0ec92019-10-21 23:01:31 +03002144 RtpTransceiverDirection::kSendOnly);
2145 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2146 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
2147 auto audio_transport =
2148 callee->pc()->GetTransceivers()[0]->receiver()->dtls_transport();
2149 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
2150 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->direction(),
2151 RtpTransceiverDirection::kSendOnly);
2152 // One way audio must remain working after rollback as local direction change
2153 // comes in effect after completing full negotiation round.
2154 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->receiver()->dtls_transport(),
2155 audio_transport);
2156}
2157
2158TEST_F(PeerConnectionJsepTest, RollbackRemoteDirectionChange) {
2159 auto caller = CreatePeerConnection();
2160 auto caller_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
2161 auto callee = CreatePeerConnection();
2162 callee->AddAudioTrack("a");
2163 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2164 EXPECT_TRUE(
2165 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
2166 // In stable make remote audio receive only.
Harald Alvestrand6060df52020-08-11 09:54:02 +02002167 caller_transceiver->SetDirectionWithError(RtpTransceiverDirection::kRecvOnly);
Eldar Relloead0ec92019-10-21 23:01:31 +03002168 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2169 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
2170 // The direction attribute is not modified by the offer.
2171 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->direction(),
2172 RtpTransceiverDirection::kSendRecv);
2173 auto audio_transport =
2174 callee->pc()->GetTransceivers()[0]->sender()->dtls_transport();
2175 EXPECT_EQ(callee->observer()->add_track_events_.size(), 1u);
2176 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 1u);
2177 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
2178 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
2179 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->direction(),
2180 RtpTransceiverDirection::kSendRecv);
2181 // One way audio must remain working after rollback.
2182 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
2183 audio_transport);
2184 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 1u);
2185}
2186
Eldar Rello5ab79e62019-10-09 18:29:44 +03002187TEST_F(PeerConnectionJsepTest, RollbackAfterMultipleSLD) {
2188 auto callee = CreatePeerConnection();
2189 callee->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
2190 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2191 callee->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2192 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
Henrik Boströme574a312020-08-25 10:20:11 +02002193 callee->observer()->clear_legacy_renegotiation_needed();
2194 callee->observer()->clear_latest_negotiation_needed_event();
Eldar Rello5ab79e62019-10-09 18:29:44 +03002195 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
Henrik Boströme574a312020-08-25 10:20:11 +02002196 EXPECT_TRUE(callee->observer()->legacy_renegotiation_needed());
2197 EXPECT_TRUE(callee->observer()->has_negotiation_needed_event());
Eldar Relloead0ec92019-10-21 23:01:31 +03002198 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 2u);
Eldar Rello5ab79e62019-10-09 18:29:44 +03002199 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), absl::nullopt);
2200 EXPECT_EQ(callee->pc()->GetTransceivers()[1]->mid(), absl::nullopt);
2201}
2202
2203TEST_F(PeerConnectionJsepTest, NoRollbackNeeded) {
2204 auto caller = CreatePeerConnection();
2205 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
2206 auto callee = CreatePeerConnection();
2207 callee->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
2208 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
2209 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
2210 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2211 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2212}
2213
Eldar Rello353a7182019-11-25 18:49:44 +02002214TEST_F(PeerConnectionJsepTest, RollbackMultipleStreamChanges) {
2215 auto callee = CreatePeerConnection();
2216 auto caller = CreatePeerConnection();
2217 caller->AddAudioTrack("a_1", {"id_1"});
2218 caller->AddVideoTrack("v_0", {"id_0"}); // Provide an extra stream id.
2219 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2220 EXPECT_TRUE(
2221 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
2222 caller->pc()->GetTransceivers()[0]->sender()->SetStreams({"id_2"});
2223 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2224 caller->pc()->GetTransceivers()[0]->sender()->SetStreams({"id_3"});
2225 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2226 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->receiver()->stream_ids()[0],
2227 "id_3");
2228 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
2229 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->receiver()->stream_ids().size(),
2230 1u);
2231 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->receiver()->stream_ids()[0],
2232 "id_1");
2233}
2234
Eldar Rellod85ea752020-02-19 20:41:07 +02002235TEST_F(PeerConnectionJsepTest, DataChannelImplicitRollback) {
2236 RTCConfiguration config;
2237 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
2238 config.enable_implicit_rollback = true;
2239 auto caller = CreatePeerConnection(config);
2240 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2241 auto callee = CreatePeerConnection(config);
2242 callee->CreateDataChannel("dummy");
2243 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2244 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2245 EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal());
Henrik Boströme574a312020-08-25 10:20:11 +02002246 EXPECT_TRUE(callee->observer()->legacy_renegotiation_needed());
2247 EXPECT_TRUE(callee->observer()->has_negotiation_needed_event());
Eldar Rellod85ea752020-02-19 20:41:07 +02002248 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2249}
2250
2251TEST_F(PeerConnectionJsepTest, RollbackRemoteDataChannelThenAddTransceiver) {
2252 auto caller = CreatePeerConnection();
2253 auto callee = CreatePeerConnection();
2254 caller->CreateDataChannel("dummy");
2255 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2256 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
2257 callee->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2258 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2259}
2260
2261TEST_F(PeerConnectionJsepTest,
2262 RollbackRemoteDataChannelThenAddTransceiverAndDataChannel) {
2263 auto caller = CreatePeerConnection();
2264 auto callee = CreatePeerConnection();
2265 caller->CreateDataChannel("dummy");
2266 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2267 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
2268 callee->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2269 callee->CreateDataChannel("dummy");
2270 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2271}
2272
2273TEST_F(PeerConnectionJsepTest, RollbackRemoteDataChannelThenAddDataChannel) {
2274 auto caller = CreatePeerConnection();
2275 auto callee = CreatePeerConnection();
2276 caller->CreateDataChannel("dummy");
2277 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2278 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
2279 callee->CreateDataChannel("dummy");
2280 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2281}
2282
2283TEST_F(PeerConnectionJsepTest, RollbackRemoteTransceiverThenAddDataChannel) {
2284 auto caller = CreatePeerConnection();
2285 auto callee = CreatePeerConnection();
2286 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2287 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2288 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
2289 callee->CreateDataChannel("dummy");
2290 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2291}
2292
2293TEST_F(PeerConnectionJsepTest,
2294 RollbackRemoteTransceiverThenAddDataChannelAndTransceiver) {
2295 auto caller = CreatePeerConnection();
2296 auto callee = CreatePeerConnection();
2297 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2298 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2299 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
2300 callee->CreateDataChannel("dummy");
2301 callee->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2302 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2303}
2304
Steve Antondcc3c022017-12-22 16:02:54 -08002305} // namespace webrtc