blob: b7c07598cfb779eb0f458ebf832bfe89c6afeef9 [file] [log] [blame]
Steve Antondcc3c022017-12-22 16:02:54 -08001/*
2 * Copyright 2017 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Mirko Bonadei317a1f02019-09-17 17:06:18 +020011#include <memory>
12
Danil Chapovalov9da25bd2019-06-20 10:19:42 +020013#include "api/task_queue/default_task_queue_factory.h"
Steve Anton10542f22019-01-11 09:11:00 -080014#include "media/engine/webrtc_media_engine.h"
Danil Chapovalov9da25bd2019-06-20 10:19:42 +020015#include "media/engine/webrtc_media_engine_defaults.h"
Steve Anton10542f22019-01-11 09:11:00 -080016#include "pc/media_session.h"
17#include "pc/peer_connection_factory.h"
18#include "pc/peer_connection_wrapper.h"
19#include "pc/sdp_utils.h"
Steve Antondcc3c022017-12-22 16:02:54 -080020#ifdef WEBRTC_ANDROID
Steve Anton10542f22019-01-11 09:11:00 -080021#include "pc/test/android_test_initializer.h"
Steve Antondcc3c022017-12-22 16:02:54 -080022#endif
Steve Anton10542f22019-01-11 09:11:00 -080023#include "pc/test/fake_audio_capture_module.h"
Björn Terelius1f580a92020-08-27 13:59:47 +000024#include "pc/test/fake_sctp_transport.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"
28
29// This file contains tests that ensure the PeerConnection's implementation of
30// CreateOffer/CreateAnswer/SetLocalDescription/SetRemoteDescription conform
31// to the JavaScript Session Establishment Protocol (JSEP).
32// For now these semantics are only available when configuring the
33// PeerConnection with Unified Plan, but eventually that will be the default.
34
35namespace webrtc {
36
37using cricket::MediaContentDescription;
38using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
Steve Antondcc3c022017-12-22 16:02:54 -080039using ::testing::Combine;
40using ::testing::ElementsAre;
Steve Antonef65ef12018-01-10 17:15:20 -080041using ::testing::UnorderedElementsAre;
Jonas Olssona4d87372019-07-05 19:08:33 +020042using ::testing::Values;
Steve Antondcc3c022017-12-22 16:02:54 -080043
Björn Terelius1f580a92020-08-27 13:59:47 +000044class PeerConnectionFactoryForJsepTest : public PeerConnectionFactory {
45 public:
46 PeerConnectionFactoryForJsepTest()
47 : PeerConnectionFactory([] {
48 PeerConnectionFactoryDependencies dependencies;
49 dependencies.worker_thread = rtc::Thread::Current();
50 dependencies.network_thread = rtc::Thread::Current();
51 dependencies.signaling_thread = rtc::Thread::Current();
52 dependencies.task_queue_factory = CreateDefaultTaskQueueFactory();
53 cricket::MediaEngineDependencies media_deps;
54 media_deps.task_queue_factory = dependencies.task_queue_factory.get();
55 media_deps.adm = FakeAudioCaptureModule::Create();
56 SetMediaEngineDefaults(&media_deps);
57 dependencies.media_engine =
58 cricket::CreateMediaEngine(std::move(media_deps));
59 dependencies.call_factory = CreateCallFactory();
60 return dependencies;
61 }()) {}
62
63 std::unique_ptr<cricket::SctpTransportInternalFactory>
64 CreateSctpTransportInternalFactory() {
65 return std::make_unique<FakeSctpTransportFactory>();
66 }
67};
Steve Antonfa2260d2017-12-28 16:38:23 -080068
Steve Antondcc3c022017-12-22 16:02:54 -080069class PeerConnectionJsepTest : public ::testing::Test {
70 protected:
71 typedef std::unique_ptr<PeerConnectionWrapper> WrapperPtr;
72
73 PeerConnectionJsepTest()
74 : vss_(new rtc::VirtualSocketServer()), main_(vss_.get()) {
75#ifdef WEBRTC_ANDROID
76 InitializeAndroidObjects();
77#endif
Steve Antondcc3c022017-12-22 16:02:54 -080078 }
79
80 WrapperPtr CreatePeerConnection() {
81 RTCConfiguration config;
82 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
83 return CreatePeerConnection(config);
84 }
85
86 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
Björn Terelius1f580a92020-08-27 13:59:47 +000087 rtc::scoped_refptr<PeerConnectionFactory> pc_factory(
88 new rtc::RefCountedObject<PeerConnectionFactoryForJsepTest>());
89 RTC_CHECK(pc_factory->Initialize());
Mirko Bonadei317a1f02019-09-17 17:06:18 +020090 auto observer = std::make_unique<MockPeerConnectionObserver>();
Steve Antonfa2260d2017-12-28 16:38:23 -080091 auto pc = pc_factory->CreatePeerConnection(config, nullptr, nullptr,
92 observer.get());
Steve Antondcc3c022017-12-22 16:02:54 -080093 if (!pc) {
94 return nullptr;
95 }
96
Yves Gerey4e933292018-10-31 15:36:05 +010097 observer->SetPeerConnectionInterface(pc.get());
Mirko Bonadei317a1f02019-09-17 17:06:18 +020098 return std::make_unique<PeerConnectionWrapper>(pc_factory, pc,
99 std::move(observer));
Steve Antondcc3c022017-12-22 16:02:54 -0800100 }
101
102 std::unique_ptr<rtc::VirtualSocketServer> vss_;
103 rtc::AutoSocketServerThread main_;
Steve Antondcc3c022017-12-22 16:02:54 -0800104};
105
106// Tests for JSEP initial offer generation.
107
108// Test that an offer created by a PeerConnection with no transceivers generates
109// no media sections.
110TEST_F(PeerConnectionJsepTest, EmptyInitialOffer) {
111 auto caller = CreatePeerConnection();
Steve Antonfa2260d2017-12-28 16:38:23 -0800112
Steve Antondcc3c022017-12-22 16:02:54 -0800113 auto offer = caller->CreateOffer();
Steve Antonfa2260d2017-12-28 16:38:23 -0800114 ASSERT_EQ(0u, offer->description()->contents().size());
Steve Antondcc3c022017-12-22 16:02:54 -0800115}
116
117// Test that an initial offer with one audio track generates one audio media
118// section.
119TEST_F(PeerConnectionJsepTest, AudioOnlyInitialOffer) {
120 auto caller = CreatePeerConnection();
121 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
Steve Antondcc3c022017-12-22 16:02:54 -0800122
Steve Antonfa2260d2017-12-28 16:38:23 -0800123 auto offer = caller->CreateOffer();
Steve Antondcc3c022017-12-22 16:02:54 -0800124 auto contents = offer->description()->contents();
125 ASSERT_EQ(1u, contents.size());
126 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, contents[0].media_description()->type());
127}
128
129// Test than an initial offer with one video track generates one video media
130// section
131TEST_F(PeerConnectionJsepTest, VideoOnlyInitialOffer) {
132 auto caller = CreatePeerConnection();
133 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
Steve Antondcc3c022017-12-22 16:02:54 -0800134
Steve Antonfa2260d2017-12-28 16:38:23 -0800135 auto offer = caller->CreateOffer();
Steve Antondcc3c022017-12-22 16:02:54 -0800136 auto contents = offer->description()->contents();
137 ASSERT_EQ(1u, contents.size());
138 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, contents[0].media_description()->type());
139}
140
Steve Antonfa2260d2017-12-28 16:38:23 -0800141// Test that an initial offer with one data channel generates one data media
142// section.
143TEST_F(PeerConnectionJsepTest, DataOnlyInitialOffer) {
144 auto caller = CreatePeerConnection();
145 caller->CreateDataChannel("dc");
146
147 auto offer = caller->CreateOffer();
148 auto contents = offer->description()->contents();
149 ASSERT_EQ(1u, contents.size());
150 EXPECT_EQ(cricket::MEDIA_TYPE_DATA, contents[0].media_description()->type());
151}
152
153// Test that creating multiple data channels only results in one data section
154// generated in the offer.
155TEST_F(PeerConnectionJsepTest, MultipleDataChannelsCreateOnlyOneDataSection) {
156 auto caller = CreatePeerConnection();
157 caller->CreateDataChannel("first");
158 caller->CreateDataChannel("second");
159 caller->CreateDataChannel("third");
160
161 auto offer = caller->CreateOffer();
162 ASSERT_EQ(1u, offer->description()->contents().size());
163}
164
Steve Antondcc3c022017-12-22 16:02:54 -0800165// Test that multiple media sections in the initial offer are ordered in the
166// order the transceivers were added to the PeerConnection. This is required by
167// JSEP section 5.2.1.
168TEST_F(PeerConnectionJsepTest, MediaSectionsInInitialOfferOrderedCorrectly) {
169 auto caller = CreatePeerConnection();
170 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
171 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
172 RtpTransceiverInit init;
173 init.direction = RtpTransceiverDirection::kSendOnly;
174 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init);
Steve Antondcc3c022017-12-22 16:02:54 -0800175
Steve Antonfa2260d2017-12-28 16:38:23 -0800176 auto offer = caller->CreateOffer();
Steve Antondcc3c022017-12-22 16:02:54 -0800177 auto contents = offer->description()->contents();
178 ASSERT_EQ(3u, contents.size());
179
180 const MediaContentDescription* media_description1 =
181 contents[0].media_description();
182 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, media_description1->type());
183 EXPECT_EQ(RtpTransceiverDirection::kSendRecv,
184 media_description1->direction());
185
186 const MediaContentDescription* media_description2 =
187 contents[1].media_description();
188 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, media_description2->type());
189 EXPECT_EQ(RtpTransceiverDirection::kSendRecv,
190 media_description2->direction());
191
192 const MediaContentDescription* media_description3 =
193 contents[2].media_description();
194 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, media_description3->type());
195 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
196 media_description3->direction());
197}
198
199// Test that media sections in the initial offer have different mids.
200TEST_F(PeerConnectionJsepTest, MediaSectionsInInitialOfferHaveDifferentMids) {
201 auto caller = CreatePeerConnection();
202 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
203 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
Steve Antonfa2260d2017-12-28 16:38:23 -0800204
Steve Antondcc3c022017-12-22 16:02:54 -0800205 auto offer = caller->CreateOffer();
Steve Antondcc3c022017-12-22 16:02:54 -0800206 auto contents = offer->description()->contents();
207 ASSERT_EQ(2u, contents.size());
208 EXPECT_NE(contents[0].name, contents[1].name);
209}
210
211TEST_F(PeerConnectionJsepTest,
212 StoppedTransceiverHasNoMediaSectionInInitialOffer) {
213 auto caller = CreatePeerConnection();
214 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
Harald Alvestrand6060df52020-08-11 09:54:02 +0200215 transceiver->StopInternal();
Steve Antondcc3c022017-12-22 16:02:54 -0800216
217 auto offer = caller->CreateOffer();
218 EXPECT_EQ(0u, offer->description()->contents().size());
219}
220
221// Tests for JSEP SetLocalDescription with a local offer.
222
223TEST_F(PeerConnectionJsepTest, SetLocalEmptyOfferCreatesNoTransceivers) {
224 auto caller = CreatePeerConnection();
Steve Antonfa2260d2017-12-28 16:38:23 -0800225
Steve Antondcc3c022017-12-22 16:02:54 -0800226 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
227
228 EXPECT_THAT(caller->pc()->GetTransceivers(), ElementsAre());
229 EXPECT_THAT(caller->pc()->GetSenders(), ElementsAre());
230 EXPECT_THAT(caller->pc()->GetReceivers(), ElementsAre());
231}
232
233TEST_F(PeerConnectionJsepTest, SetLocalOfferSetsTransceiverMid) {
234 auto caller = CreatePeerConnection();
235 auto audio_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
236 auto video_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
237
238 auto offer = caller->CreateOffer();
239 std::string audio_mid = offer->description()->contents()[0].name;
240 std::string video_mid = offer->description()->contents()[1].name;
241
242 ASSERT_TRUE(caller->SetLocalDescription(std::move(offer)));
243
244 EXPECT_EQ(audio_mid, audio_transceiver->mid());
245 EXPECT_EQ(video_mid, video_transceiver->mid());
246}
247
248// Tests for JSEP SetRemoteDescription with a remote offer.
249
250// Test that setting a remote offer with sendrecv audio and video creates two
251// transceivers, one for receiving audio and one for receiving video.
252TEST_F(PeerConnectionJsepTest, SetRemoteOfferCreatesTransceivers) {
253 auto caller = CreatePeerConnection();
254 auto caller_audio = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
255 auto caller_video = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
256 auto callee = CreatePeerConnection();
257
258 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
259
260 auto transceivers = callee->pc()->GetTransceivers();
261 ASSERT_EQ(2u, transceivers.size());
Steve Anton1bc97162018-06-25 14:04:01 -0700262
Steve Anton69470252018-02-09 11:43:08 -0800263 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, transceivers[0]->media_type());
Steve Antondcc3c022017-12-22 16:02:54 -0800264 EXPECT_EQ(caller_audio->mid(), transceivers[0]->mid());
265 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly, transceivers[0]->direction());
Steve Anton1bc97162018-06-25 14:04:01 -0700266 EXPECT_EQ(0u, transceivers[0]->sender()->stream_ids().size());
267
Steve Anton69470252018-02-09 11:43:08 -0800268 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, transceivers[1]->media_type());
Steve Antondcc3c022017-12-22 16:02:54 -0800269 EXPECT_EQ(caller_video->mid(), transceivers[1]->mid());
270 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly, transceivers[1]->direction());
Steve Anton1bc97162018-06-25 14:04:01 -0700271 EXPECT_EQ(0u, transceivers[1]->sender()->stream_ids().size());
Steve Antondcc3c022017-12-22 16:02:54 -0800272}
273
274// Test that setting a remote offer with an audio track will reuse the
275// transceiver created for a local audio track added by AddTrack.
276// This is specified in JSEP section 5.10 (Applying a Remote Description). The
277// intent is to preserve backwards compatibility with clients who only use the
278// AddTrack API.
279TEST_F(PeerConnectionJsepTest, SetRemoteOfferReusesTransceiverFromAddTrack) {
280 auto caller = CreatePeerConnection();
281 caller->AddAudioTrack("a");
282 auto caller_audio = caller->pc()->GetTransceivers()[0];
283 auto callee = CreatePeerConnection();
284 callee->AddAudioTrack("a");
285
286 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
287
288 auto transceivers = callee->pc()->GetTransceivers();
289 ASSERT_EQ(1u, transceivers.size());
290 EXPECT_EQ(MediaStreamTrackInterface::kAudioKind,
291 transceivers[0]->receiver()->track()->kind());
292 EXPECT_EQ(caller_audio->mid(), transceivers[0]->mid());
293}
294
295// Test that setting a remote offer with an audio track marked sendonly will not
296// reuse a transceiver created by AddTrack. JSEP only allows the transceiver to
297// be reused if the offer direction is sendrecv or recvonly.
298TEST_F(PeerConnectionJsepTest,
299 SetRemoteOfferDoesNotReuseTransceiverIfDirectionSendOnly) {
300 auto caller = CreatePeerConnection();
301 caller->AddAudioTrack("a");
302 auto caller_audio = caller->pc()->GetTransceivers()[0];
Harald Alvestrand6060df52020-08-11 09:54:02 +0200303 caller_audio->SetDirectionWithError(RtpTransceiverDirection::kSendOnly);
Steve Antondcc3c022017-12-22 16:02:54 -0800304 auto callee = CreatePeerConnection();
305 callee->AddAudioTrack("a");
306
307 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
308
309 auto transceivers = callee->pc()->GetTransceivers();
310 ASSERT_EQ(2u, transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200311 EXPECT_EQ(absl::nullopt, transceivers[0]->mid());
Steve Antondcc3c022017-12-22 16:02:54 -0800312 EXPECT_EQ(caller_audio->mid(), transceivers[1]->mid());
313}
314
315// Test that setting a remote offer with an audio track will not reuse a
316// transceiver added by AddTransceiver. The logic for reusing a transceiver is
317// specific to those added by AddTrack and is tested above.
318TEST_F(PeerConnectionJsepTest,
319 SetRemoteOfferDoesNotReuseTransceiverFromAddTransceiver) {
320 auto caller = CreatePeerConnection();
321 caller->AddAudioTrack("a");
322 auto callee = CreatePeerConnection();
323 auto transceiver = callee->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
324
325 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
326
327 auto transceivers = callee->pc()->GetTransceivers();
328 ASSERT_EQ(2u, transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200329 EXPECT_EQ(absl::nullopt, transceivers[0]->mid());
Steve Antondcc3c022017-12-22 16:02:54 -0800330 EXPECT_EQ(caller->pc()->GetTransceivers()[0]->mid(), transceivers[1]->mid());
331 EXPECT_EQ(MediaStreamTrackInterface::kAudioKind,
332 transceivers[1]->receiver()->track()->kind());
333}
334
335// Test that setting a remote offer with an audio track will not reuse a
336// transceiver created for a local video track added by AddTrack.
337TEST_F(PeerConnectionJsepTest,
338 SetRemoteOfferDoesNotReuseTransceiverOfWrongType) {
339 auto caller = CreatePeerConnection();
340 caller->AddAudioTrack("a");
341 auto callee = CreatePeerConnection();
342 auto video_sender = callee->AddVideoTrack("v");
343
344 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
345
346 auto transceivers = callee->pc()->GetTransceivers();
347 ASSERT_EQ(2u, transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200348 EXPECT_EQ(absl::nullopt, transceivers[0]->mid());
Steve Antondcc3c022017-12-22 16:02:54 -0800349 EXPECT_EQ(caller->pc()->GetTransceivers()[0]->mid(), transceivers[1]->mid());
350 EXPECT_EQ(MediaStreamTrackInterface::kAudioKind,
351 transceivers[1]->receiver()->track()->kind());
352}
353
354// Test that setting a remote offer with an audio track will not reuse a
355// stopped transceiver.
356TEST_F(PeerConnectionJsepTest, SetRemoteOfferDoesNotReuseStoppedTransceiver) {
357 auto caller = CreatePeerConnection();
358 caller->AddAudioTrack("a");
359 auto callee = CreatePeerConnection();
360 callee->AddAudioTrack("a");
Harald Alvestrand6060df52020-08-11 09:54:02 +0200361 callee->pc()->GetTransceivers()[0]->StopInternal();
Steve Antondcc3c022017-12-22 16:02:54 -0800362
363 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
364
365 auto transceivers = callee->pc()->GetTransceivers();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200366 ASSERT_EQ(1u, transceivers.size());
367 EXPECT_EQ(caller->pc()->GetTransceivers()[0]->mid(), transceivers[0]->mid());
368 EXPECT_FALSE(transceivers[0]->stopped());
Steve Antondcc3c022017-12-22 16:02:54 -0800369}
370
371// Test that audio and video transceivers created on the remote side with
372// AddTrack will all be reused if there is the same number of audio/video tracks
373// in the remote offer. Additionally, this tests that transceivers are
374// successfully matched even if they are in a different order on the remote
375// side.
376TEST_F(PeerConnectionJsepTest, SetRemoteOfferReusesTransceiversOfBothTypes) {
377 auto caller = CreatePeerConnection();
378 caller->AddVideoTrack("v");
379 caller->AddAudioTrack("a");
380 auto callee = CreatePeerConnection();
381 callee->AddAudioTrack("a");
382 callee->AddVideoTrack("v");
383
384 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
385
386 auto caller_transceivers = caller->pc()->GetTransceivers();
387 auto callee_transceivers = callee->pc()->GetTransceivers();
388 ASSERT_EQ(2u, callee_transceivers.size());
389 EXPECT_EQ(caller_transceivers[0]->mid(), callee_transceivers[1]->mid());
390 EXPECT_EQ(caller_transceivers[1]->mid(), callee_transceivers[0]->mid());
391}
392
393// Tests for JSEP initial CreateAnswer.
394
395// Test that the answer to a remote offer creates media sections for each
396// offered media in the same order and with the same mids.
397TEST_F(PeerConnectionJsepTest, CreateAnswerHasSameMidsAsOffer) {
398 auto caller = CreatePeerConnection();
399 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
400 auto second_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
401 auto third_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
Steve Antonfa2260d2017-12-28 16:38:23 -0800402 caller->CreateDataChannel("dc");
Steve Antondcc3c022017-12-22 16:02:54 -0800403 auto callee = CreatePeerConnection();
404
Steve Antonfa2260d2017-12-28 16:38:23 -0800405 auto offer = caller->CreateOffer();
406 const auto* offer_data = cricket::GetFirstDataContent(offer->description());
407 ASSERT_TRUE(
408 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
409 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
Steve Antondcc3c022017-12-22 16:02:54 -0800410
411 auto answer = callee->CreateAnswer();
412 auto contents = answer->description()->contents();
Steve Antonfa2260d2017-12-28 16:38:23 -0800413 ASSERT_EQ(4u, contents.size());
Steve Antondcc3c022017-12-22 16:02:54 -0800414 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, contents[0].media_description()->type());
Steve Antonfa2260d2017-12-28 16:38:23 -0800415 EXPECT_EQ(first_transceiver->mid(), contents[0].name);
Steve Antondcc3c022017-12-22 16:02:54 -0800416 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, contents[1].media_description()->type());
Steve Antonfa2260d2017-12-28 16:38:23 -0800417 EXPECT_EQ(second_transceiver->mid(), contents[1].name);
Steve Antondcc3c022017-12-22 16:02:54 -0800418 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, contents[2].media_description()->type());
Steve Antonfa2260d2017-12-28 16:38:23 -0800419 EXPECT_EQ(third_transceiver->mid(), contents[2].name);
420 EXPECT_EQ(cricket::MEDIA_TYPE_DATA, contents[3].media_description()->type());
421 EXPECT_EQ(offer_data->name, contents[3].name);
Steve Antondcc3c022017-12-22 16:02:54 -0800422}
423
424// Test that an answering media section is marked as rejected if the underlying
425// transceiver has been stopped.
426TEST_F(PeerConnectionJsepTest, CreateAnswerRejectsStoppedTransceiver) {
427 auto caller = CreatePeerConnection();
428 caller->AddAudioTrack("a");
429 auto callee = CreatePeerConnection();
430
431 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
432
Harald Alvestrand6060df52020-08-11 09:54:02 +0200433 callee->pc()->GetTransceivers()[0]->StopInternal();
Steve Antondcc3c022017-12-22 16:02:54 -0800434
435 auto answer = callee->CreateAnswer();
436 auto contents = answer->description()->contents();
437 ASSERT_EQ(1u, contents.size());
438 EXPECT_TRUE(contents[0].rejected);
439}
440
441// Test that CreateAnswer will generate media sections which will only send or
442// receive if the offer indicates it can do the reciprocating direction.
443// The full matrix is tested more extensively in MediaSession.
444TEST_F(PeerConnectionJsepTest, CreateAnswerNegotiatesDirection) {
445 auto caller = CreatePeerConnection();
446 RtpTransceiverInit init;
447 init.direction = RtpTransceiverDirection::kSendOnly;
448 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init);
449 auto callee = CreatePeerConnection();
450 callee->AddAudioTrack("a");
451
452 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
453
454 auto answer = callee->CreateAnswer();
455 auto contents = answer->description()->contents();
456 ASSERT_EQ(1u, contents.size());
457 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
458 contents[0].media_description()->direction());
459}
460
461// Tests for JSEP SetLocalDescription with a local answer.
462// Note that these test only the additional behaviors not covered by
463// SetLocalDescription with a local offer.
464
465// Test that SetLocalDescription with an answer sets the current_direction
466// property of the transceivers mentioned in the session description.
467TEST_F(PeerConnectionJsepTest, SetLocalAnswerUpdatesCurrentDirection) {
468 auto caller = CreatePeerConnection();
469 auto caller_audio = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
Harald Alvestrand6060df52020-08-11 09:54:02 +0200470 caller_audio->SetDirectionWithError(RtpTransceiverDirection::kRecvOnly);
Steve Antondcc3c022017-12-22 16:02:54 -0800471 auto callee = CreatePeerConnection();
472 callee->AddAudioTrack("a");
473
474 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
475 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
476
477 auto transceivers = callee->pc()->GetTransceivers();
478 ASSERT_EQ(1u, transceivers.size());
479 // Since the offer was recvonly and the transceiver direction is sendrecv,
480 // the negotiated direction will be sendonly.
481 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
482 transceivers[0]->current_direction());
483}
484
485// Tests for JSEP SetRemoteDescription with a remote answer.
486// Note that these test only the additional behaviors not covered by
487// SetRemoteDescription with a remote offer.
488
489TEST_F(PeerConnectionJsepTest, SetRemoteAnswerUpdatesCurrentDirection) {
490 auto caller = CreatePeerConnection();
491 caller->AddAudioTrack("a");
492 auto callee = CreatePeerConnection();
493 callee->AddAudioTrack("a");
494 auto callee_audio = callee->pc()->GetTransceivers()[0];
Harald Alvestrand6060df52020-08-11 09:54:02 +0200495 callee_audio->SetDirectionWithError(RtpTransceiverDirection::kSendOnly);
Steve Antondcc3c022017-12-22 16:02:54 -0800496
497 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
498 ASSERT_TRUE(
499 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
500
501 auto transceivers = caller->pc()->GetTransceivers();
502 ASSERT_EQ(1u, transceivers.size());
503 // Since the remote transceiver was set to sendonly, the negotiated direction
504 // in the answer would be sendonly which we apply as recvonly to the local
505 // transceiver.
506 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
507 transceivers[0]->current_direction());
508}
509
510// Tests for multiple round trips.
511
512// Test that setting a transceiver with the inactive direction does not stop it
513// on either the caller or the callee.
514TEST_F(PeerConnectionJsepTest, SettingTransceiverInactiveDoesNotStopIt) {
515 auto caller = CreatePeerConnection();
516 caller->AddAudioTrack("a");
517 auto callee = CreatePeerConnection();
518 callee->AddAudioTrack("a");
Harald Alvestrand6060df52020-08-11 09:54:02 +0200519 callee->pc()->GetTransceivers()[0]->SetDirectionWithError(
Steve Antondcc3c022017-12-22 16:02:54 -0800520 RtpTransceiverDirection::kInactive);
521
522 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
523 ASSERT_TRUE(
524 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
525
526 EXPECT_FALSE(caller->pc()->GetTransceivers()[0]->stopped());
527 EXPECT_FALSE(callee->pc()->GetTransceivers()[0]->stopped());
528}
529
530// Test that if a transceiver had been associated and later stopped, then a
531// media section is still generated for it and the media section is marked as
532// rejected.
533TEST_F(PeerConnectionJsepTest,
534 ReOfferMediaSectionForAssociatedStoppedTransceiverIsRejected) {
535 auto caller = CreatePeerConnection();
536 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
537 auto callee = CreatePeerConnection();
538
539 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
540 ASSERT_TRUE(
541 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
542
543 ASSERT_TRUE(transceiver->mid());
Harald Alvestrand6060df52020-08-11 09:54:02 +0200544 transceiver->StopInternal();
Steve Antondcc3c022017-12-22 16:02:54 -0800545
546 auto reoffer = caller->CreateOffer();
547 auto contents = reoffer->description()->contents();
548 ASSERT_EQ(1u, contents.size());
549 EXPECT_TRUE(contents[0].rejected);
550}
551
552// Test that stopping an associated transceiver on the caller side will stop the
553// corresponding transceiver on the remote side when the remote offer is
554// applied.
555TEST_F(PeerConnectionJsepTest,
556 StoppingTransceiverInOfferStopsTransceiverOnRemoteSide) {
557 auto caller = CreatePeerConnection();
558 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
559 auto callee = CreatePeerConnection();
560
561 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
562 ASSERT_TRUE(
563 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
564
Harald Alvestrand6060df52020-08-11 09:54:02 +0200565 transceiver->StopInternal();
Steve Antondcc3c022017-12-22 16:02:54 -0800566
567 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
568
569 auto transceivers = callee->pc()->GetTransceivers();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200570 EXPECT_EQ(0u, transceivers.size());
Steve Antondcc3c022017-12-22 16:02:54 -0800571}
572
573// Test that CreateOffer will only generate a recycled media section if the
574// transceiver to be recycled has been seen stopped by the other side first.
575TEST_F(PeerConnectionJsepTest,
576 CreateOfferDoesNotRecycleMediaSectionIfFirstStopped) {
577 auto caller = CreatePeerConnection();
578 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
579 auto callee = CreatePeerConnection();
580
581 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
582 ASSERT_TRUE(
583 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
584
585 auto second_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
Harald Alvestrand6060df52020-08-11 09:54:02 +0200586 first_transceiver->StopInternal();
Steve Antondcc3c022017-12-22 16:02:54 -0800587
588 auto reoffer = caller->CreateOffer();
589 auto contents = reoffer->description()->contents();
590 ASSERT_EQ(2u, contents.size());
591 EXPECT_TRUE(contents[0].rejected);
592 EXPECT_FALSE(contents[1].rejected);
593}
594
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800595// Test that the offer/answer and the transceivers are correctly generated and
596// updated when the media section is recycled after the callee stops a
597// transceiver and sends an answer with a 0 port.
598TEST_F(PeerConnectionJsepTest,
599 RecycleMediaSectionWhenStoppingTransceiverOnAnswerer) {
600 auto caller = CreatePeerConnection();
601 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
602 auto callee = CreatePeerConnection();
603
604 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
Harald Alvestrand6060df52020-08-11 09:54:02 +0200605 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
606 callee->pc()->GetTransceivers()[0]->StopInternal();
607 ASSERT_EQ(0u, callee->pc()->GetTransceivers().size());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800608 ASSERT_TRUE(
609 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
610 EXPECT_TRUE(first_transceiver->stopped());
Harald Alvestrand6060df52020-08-11 09:54:02 +0200611 // First transceivers aren't dissociated yet on caller side.
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200612 ASSERT_NE(absl::nullopt, first_transceiver->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800613 std::string first_mid = *first_transceiver->mid();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200614 // They are disassociated on callee side.
615 ASSERT_EQ(0u, callee->pc()->GetTransceivers().size());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800616
617 // New offer exchange with new transceivers that recycles the m section
618 // correctly.
619 caller->AddAudioTrack("audio2");
620 callee->AddAudioTrack("audio2");
621 auto offer = caller->CreateOffer();
622 auto offer_contents = offer->description()->contents();
623 std::string second_mid = offer_contents[0].name;
624 ASSERT_EQ(1u, offer_contents.size());
625 EXPECT_FALSE(offer_contents[0].rejected);
626 EXPECT_NE(first_mid, second_mid);
627
628 // Setting the offer on each side will dissociate the first transceivers and
629 // associate the new transceivers.
630 ASSERT_TRUE(
631 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200632 EXPECT_EQ(absl::nullopt, first_transceiver->mid());
Harald Alvestrand6060df52020-08-11 09:54:02 +0200633 ASSERT_EQ(1u, caller->pc()->GetTransceivers().size());
634 EXPECT_EQ(second_mid, caller->pc()->GetTransceivers()[0]->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800635 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
Harald Alvestrand6060df52020-08-11 09:54:02 +0200636 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
637 EXPECT_EQ(second_mid, callee->pc()->GetTransceivers()[0]->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800638
639 // The new answer should also recycle the m section correctly.
640 auto answer = callee->CreateAnswer();
641 auto answer_contents = answer->description()->contents();
642 ASSERT_EQ(1u, answer_contents.size());
643 EXPECT_FALSE(answer_contents[0].rejected);
644 EXPECT_EQ(second_mid, answer_contents[0].name);
645
646 // Finishing the negotiation shouldn't add or dissociate any transceivers.
647 ASSERT_TRUE(
648 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
649 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
650 auto caller_transceivers = caller->pc()->GetTransceivers();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200651 ASSERT_EQ(1u, caller_transceivers.size());
652 EXPECT_EQ(second_mid, caller_transceivers[0]->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800653 auto callee_transceivers = callee->pc()->GetTransceivers();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200654 ASSERT_EQ(1u, callee_transceivers.size());
655 EXPECT_EQ(second_mid, callee_transceivers[0]->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800656}
657
658// Test that creating/setting a local offer that recycles an m= section is
659// idempotent.
660TEST_F(PeerConnectionJsepTest, CreateOfferRecyclesWhenOfferingTwice) {
661 // Do a negotiation with a port 0 for the media section.
662 auto caller = CreatePeerConnection();
663 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
664 auto callee = CreatePeerConnection();
665 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Harald Alvestrand6060df52020-08-11 09:54:02 +0200666 first_transceiver->StopInternal();
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800667 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
668 caller->AddAudioTrack("audio2");
669
670 // Create a new offer that recycles the media section and set it as a local
671 // description.
672 auto offer = caller->CreateOffer();
673 auto offer_contents = offer->description()->contents();
674 ASSERT_EQ(1u, offer_contents.size());
675 EXPECT_FALSE(offer_contents[0].rejected);
676 ASSERT_TRUE(caller->SetLocalDescription(std::move(offer)));
Harald Alvestrand6060df52020-08-11 09:54:02 +0200677 ASSERT_EQ(1u, caller->pc()->GetTransceivers().size());
678 EXPECT_FALSE(caller->pc()->GetTransceivers()[0]->stopped());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800679 std::string second_mid = offer_contents[0].name;
680
681 // Create another new offer and set the local description again without the
682 // rest of any negotation ocurring.
683 auto second_offer = caller->CreateOffer();
684 auto second_offer_contents = second_offer->description()->contents();
685 ASSERT_EQ(1u, second_offer_contents.size());
686 EXPECT_FALSE(second_offer_contents[0].rejected);
687 // The mid shouldn't change.
688 EXPECT_EQ(second_mid, second_offer_contents[0].name);
689
690 ASSERT_TRUE(caller->SetLocalDescription(std::move(second_offer)));
691 // Make sure that the caller's transceivers are associated correctly.
692 auto caller_transceivers = caller->pc()->GetTransceivers();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200693 ASSERT_EQ(1u, caller_transceivers.size());
694 EXPECT_EQ(second_mid, caller_transceivers[0]->mid());
695 EXPECT_FALSE(caller_transceivers[0]->stopped());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800696}
697
Steve Antondcc3c022017-12-22 16:02:54 -0800698// Test that the offer/answer and transceivers for both the caller and callee
699// side are generated/updated correctly when recycling an audio/video media
700// section as a media section of either the same or opposite type.
Steve Anton5c72e712018-12-10 14:25:30 -0800701// Correct recycling works as follows:
702// - The m= section is re-offered with a new MID value and the new media type.
703// - The previously-associated transceiver is dissociated when the new offer is
704// set as a local description on the offerer or as a remote description on
705// the answerer.
706// - The new transceiver is associated with the new MID value.
Steve Antondcc3c022017-12-22 16:02:54 -0800707class RecycleMediaSectionTest
708 : public PeerConnectionJsepTest,
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200709 public ::testing::WithParamInterface<
Steve Antondcc3c022017-12-22 16:02:54 -0800710 std::tuple<cricket::MediaType, cricket::MediaType>> {
711 protected:
712 RecycleMediaSectionTest() {
713 first_type_ = std::get<0>(GetParam());
714 second_type_ = std::get<1>(GetParam());
715 }
716
717 cricket::MediaType first_type_;
718 cricket::MediaType second_type_;
719};
720
Steve Anton5c72e712018-12-10 14:25:30 -0800721// Test that recycling works properly when a new transceiver recycles an m=
722// section that was rejected in both the current local and remote descriptions.
723TEST_P(RecycleMediaSectionTest, CurrentLocalAndCurrentRemoteRejected) {
Steve Antondcc3c022017-12-22 16:02:54 -0800724 auto caller = CreatePeerConnection();
725 auto first_transceiver = caller->AddTransceiver(first_type_);
726 auto callee = CreatePeerConnection();
727
728 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
729
730 std::string first_mid = *first_transceiver->mid();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200731 first_transceiver->StopInternal();
Steve Antondcc3c022017-12-22 16:02:54 -0800732
733 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
734
735 auto second_transceiver = caller->AddTransceiver(second_type_);
736
737 // The offer should reuse the previous media section but allocate a new MID
738 // and change the media type.
739 auto offer = caller->CreateOffer();
740 auto offer_contents = offer->description()->contents();
741 ASSERT_EQ(1u, offer_contents.size());
742 EXPECT_FALSE(offer_contents[0].rejected);
743 EXPECT_EQ(second_type_, offer_contents[0].media_description()->type());
744 std::string second_mid = offer_contents[0].name;
745 EXPECT_NE(first_mid, second_mid);
746
747 // Setting the local offer will dissociate the previous transceiver and set
748 // the MID for the new transceiver.
749 ASSERT_TRUE(
750 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200751 EXPECT_EQ(absl::nullopt, first_transceiver->mid());
Steve Antondcc3c022017-12-22 16:02:54 -0800752 EXPECT_EQ(second_mid, second_transceiver->mid());
753
754 // Setting the remote offer will dissociate the previous transceiver and
755 // create a new transceiver for the media section.
756 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
757 auto callee_transceivers = callee->pc()->GetTransceivers();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200758 ASSERT_EQ(1u, callee_transceivers.size());
759 EXPECT_EQ(second_mid, callee_transceivers[0]->mid());
760 EXPECT_EQ(second_type_, callee_transceivers[0]->media_type());
Steve Antondcc3c022017-12-22 16:02:54 -0800761
762 // The answer should have only one media section for the new transceiver.
763 auto answer = callee->CreateAnswer();
764 auto answer_contents = answer->description()->contents();
765 ASSERT_EQ(1u, answer_contents.size());
766 EXPECT_FALSE(answer_contents[0].rejected);
767 EXPECT_EQ(second_mid, answer_contents[0].name);
768 EXPECT_EQ(second_type_, answer_contents[0].media_description()->type());
769
770 // Setting the local answer should succeed.
771 ASSERT_TRUE(
772 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
773
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800774 // Setting the remote answer should succeed and not create any new
775 // transceivers.
Steve Antondcc3c022017-12-22 16:02:54 -0800776 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
Harald Alvestrand6060df52020-08-11 09:54:02 +0200777 ASSERT_EQ(1u, caller->pc()->GetTransceivers().size());
778 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
Steve Antondcc3c022017-12-22 16:02:54 -0800779}
780
Steve Anton5c72e712018-12-10 14:25:30 -0800781// Test that recycling works properly when a new transceiver recycles an m=
782// section that was rejected in only the current remote description.
783TEST_P(RecycleMediaSectionTest, CurrentRemoteOnlyRejected) {
784 auto caller = CreatePeerConnection();
785 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
786 auto callee = CreatePeerConnection();
787
788 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
789
790 std::string first_mid = *caller_first_transceiver->mid();
791 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
792 auto callee_first_transceiver = callee->pc()->GetTransceivers()[0];
Harald Alvestrand6060df52020-08-11 09:54:02 +0200793 callee_first_transceiver->StopInternal();
Steve Anton5c72e712018-12-10 14:25:30 -0800794
795 // The answer will have a rejected m= section.
796 ASSERT_TRUE(
797 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
798
799 // The offer should reuse the previous media section but allocate a new MID
800 // and change the media type.
801 auto caller_second_transceiver = caller->AddTransceiver(second_type_);
802 auto offer = caller->CreateOffer();
803 const auto& offer_contents = offer->description()->contents();
804 ASSERT_EQ(1u, offer_contents.size());
805 EXPECT_FALSE(offer_contents[0].rejected);
806 EXPECT_EQ(second_type_, offer_contents[0].media_description()->type());
807 std::string second_mid = offer_contents[0].name;
808 EXPECT_NE(first_mid, second_mid);
809
810 // Setting the local offer will dissociate the previous transceiver and set
811 // the MID for the new transceiver.
812 ASSERT_TRUE(
813 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
814 EXPECT_EQ(absl::nullopt, caller_first_transceiver->mid());
815 EXPECT_EQ(second_mid, caller_second_transceiver->mid());
816
817 // Setting the remote offer will dissociate the previous transceiver and
818 // create a new transceiver for the media section.
819 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
820 auto callee_transceivers = callee->pc()->GetTransceivers();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200821 ASSERT_EQ(1u, callee_transceivers.size());
822 EXPECT_EQ(second_mid, callee_transceivers[0]->mid());
823 EXPECT_EQ(second_type_, callee_transceivers[0]->media_type());
Steve Anton5c72e712018-12-10 14:25:30 -0800824
825 // The answer should have only one media section for the new transceiver.
826 auto answer = callee->CreateAnswer();
827 auto answer_contents = answer->description()->contents();
828 ASSERT_EQ(1u, answer_contents.size());
829 EXPECT_FALSE(answer_contents[0].rejected);
830 EXPECT_EQ(second_mid, answer_contents[0].name);
831 EXPECT_EQ(second_type_, answer_contents[0].media_description()->type());
832
833 // Setting the local answer should succeed.
834 ASSERT_TRUE(
835 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
836
837 // Setting the remote answer should succeed and not create any new
838 // transceivers.
839 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
Harald Alvestrand6060df52020-08-11 09:54:02 +0200840 ASSERT_EQ(1u, caller->pc()->GetTransceivers().size());
841 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
Steve Anton5c72e712018-12-10 14:25:30 -0800842}
843
844// Test that recycling works properly when a new transceiver recycles an m=
845// section that was rejected only in the current local description.
846TEST_P(RecycleMediaSectionTest, CurrentLocalOnlyRejected) {
847 auto caller = CreatePeerConnection();
848 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
849 auto callee = CreatePeerConnection();
850
851 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
852
853 std::string first_mid = *caller_first_transceiver->mid();
854 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
855 auto callee_first_transceiver = callee->pc()->GetTransceivers()[0];
Harald Alvestrand6060df52020-08-11 09:54:02 +0200856 callee_first_transceiver->StopInternal();
Steve Anton5c72e712018-12-10 14:25:30 -0800857
858 // The answer will have a rejected m= section.
859 ASSERT_TRUE(
860 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
861
862 // The offer should reuse the previous media section but allocate a new MID
863 // and change the media type.
864 auto callee_second_transceiver = callee->AddTransceiver(second_type_);
865 auto offer = callee->CreateOffer();
866 const auto& offer_contents = offer->description()->contents();
867 ASSERT_EQ(1u, offer_contents.size());
868 EXPECT_FALSE(offer_contents[0].rejected);
869 EXPECT_EQ(second_type_, offer_contents[0].media_description()->type());
870 std::string second_mid = offer_contents[0].name;
871 EXPECT_NE(first_mid, second_mid);
872
873 // Setting the local offer will dissociate the previous transceiver and set
874 // the MID for the new transceiver.
875 ASSERT_TRUE(
876 callee->SetLocalDescription(CloneSessionDescription(offer.get())));
877 EXPECT_EQ(absl::nullopt, callee_first_transceiver->mid());
878 EXPECT_EQ(second_mid, callee_second_transceiver->mid());
879
880 // Setting the remote offer will dissociate the previous transceiver and
881 // create a new transceiver for the media section.
882 ASSERT_TRUE(caller->SetRemoteDescription(std::move(offer)));
883 auto caller_transceivers = caller->pc()->GetTransceivers();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200884 ASSERT_EQ(1u, caller_transceivers.size());
885 EXPECT_EQ(second_mid, caller_transceivers[0]->mid());
886 EXPECT_EQ(second_type_, caller_transceivers[0]->media_type());
Steve Anton5c72e712018-12-10 14:25:30 -0800887
888 // The answer should have only one media section for the new transceiver.
889 auto answer = caller->CreateAnswer();
890 auto answer_contents = answer->description()->contents();
891 ASSERT_EQ(1u, answer_contents.size());
892 EXPECT_FALSE(answer_contents[0].rejected);
893 EXPECT_EQ(second_mid, answer_contents[0].name);
894 EXPECT_EQ(second_type_, answer_contents[0].media_description()->type());
895
896 // Setting the local answer should succeed.
897 ASSERT_TRUE(
898 caller->SetLocalDescription(CloneSessionDescription(answer.get())));
899
900 // Setting the remote answer should succeed and not create any new
901 // transceivers.
902 ASSERT_TRUE(callee->SetRemoteDescription(std::move(answer)));
Harald Alvestrand6060df52020-08-11 09:54:02 +0200903 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
904 ASSERT_EQ(1u, caller->pc()->GetTransceivers().size());
Steve Anton5c72e712018-12-10 14:25:30 -0800905}
906
907// Test that a m= section is *not* recycled if the media section is only
908// rejected in the pending local description and there is no current remote
909// description.
910TEST_P(RecycleMediaSectionTest, PendingLocalRejectedAndNoRemote) {
911 auto caller = CreatePeerConnection();
912 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
913
914 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
915
916 std::string first_mid = *caller_first_transceiver->mid();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200917 caller_first_transceiver->StopInternal();
Steve Anton5c72e712018-12-10 14:25:30 -0800918
919 // The reoffer will have a rejected m= section.
920 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
921
922 auto caller_second_transceiver = caller->AddTransceiver(second_type_);
923
924 // The reoffer should not recycle the existing m= section since it is not
925 // rejected in either the *current* local or *current* remote description.
926 auto reoffer = caller->CreateOffer();
927 auto reoffer_contents = reoffer->description()->contents();
928 ASSERT_EQ(2u, reoffer_contents.size());
929 EXPECT_TRUE(reoffer_contents[0].rejected);
930 EXPECT_EQ(first_type_, reoffer_contents[0].media_description()->type());
931 EXPECT_EQ(first_mid, reoffer_contents[0].name);
932 EXPECT_FALSE(reoffer_contents[1].rejected);
933 EXPECT_EQ(second_type_, reoffer_contents[1].media_description()->type());
934 std::string second_mid = reoffer_contents[1].name;
935 EXPECT_NE(first_mid, second_mid);
936
937 ASSERT_TRUE(caller->SetLocalDescription(std::move(reoffer)));
938
939 // Both RtpTransceivers are associated.
940 EXPECT_EQ(first_mid, caller_first_transceiver->mid());
941 EXPECT_EQ(second_mid, caller_second_transceiver->mid());
942}
943
944// Test that a m= section is *not* recycled if the media section is only
945// rejected in the pending local description and not rejected in the current
946// remote description.
947TEST_P(RecycleMediaSectionTest, PendingLocalRejectedAndNotRejectedRemote) {
948 auto caller = CreatePeerConnection();
949 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
950 auto callee = CreatePeerConnection();
951
952 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
953
954 std::string first_mid = *caller_first_transceiver->mid();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200955 caller_first_transceiver->StopInternal();
Steve Anton5c72e712018-12-10 14:25:30 -0800956
957 // The reoffer will have a rejected m= section.
958 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
959
960 auto caller_second_transceiver = caller->AddTransceiver(second_type_);
961
962 // The reoffer should not recycle the existing m= section since it is not
963 // rejected in either the *current* local or *current* remote description.
964 auto reoffer = caller->CreateOffer();
965 auto reoffer_contents = reoffer->description()->contents();
966 ASSERT_EQ(2u, reoffer_contents.size());
967 EXPECT_TRUE(reoffer_contents[0].rejected);
968 EXPECT_EQ(first_type_, reoffer_contents[0].media_description()->type());
969 EXPECT_EQ(first_mid, reoffer_contents[0].name);
970 EXPECT_FALSE(reoffer_contents[1].rejected);
971 EXPECT_EQ(second_type_, reoffer_contents[1].media_description()->type());
972 std::string second_mid = reoffer_contents[1].name;
973 EXPECT_NE(first_mid, second_mid);
974
975 ASSERT_TRUE(caller->SetLocalDescription(std::move(reoffer)));
976
977 // Both RtpTransceivers are associated.
978 EXPECT_EQ(first_mid, caller_first_transceiver->mid());
979 EXPECT_EQ(second_mid, caller_second_transceiver->mid());
980}
981
982// Test that an m= section is *not* recycled if the media section is only
983// rejected in the pending remote description and there is no current local
984// description.
985TEST_P(RecycleMediaSectionTest, PendingRemoteRejectedAndNoLocal) {
986 auto caller = CreatePeerConnection();
987 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
988 auto callee = CreatePeerConnection();
989
990 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
991
992 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
993 auto callee_first_transceiver = callee->pc()->GetTransceivers()[0];
994 std::string first_mid = *callee_first_transceiver->mid();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200995 caller_first_transceiver->StopInternal();
Steve Anton5c72e712018-12-10 14:25:30 -0800996
997 // The reoffer will have a rejected m= section.
998 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
999
1000 auto callee_second_transceiver = callee->AddTransceiver(second_type_);
1001
1002 // The reoffer should not recycle the existing m= section since it is not
1003 // rejected in either the *current* local or *current* remote description.
1004 auto reoffer = callee->CreateOffer();
1005 auto reoffer_contents = reoffer->description()->contents();
1006 ASSERT_EQ(2u, reoffer_contents.size());
1007 EXPECT_TRUE(reoffer_contents[0].rejected);
1008 EXPECT_EQ(first_type_, reoffer_contents[0].media_description()->type());
1009 EXPECT_EQ(first_mid, reoffer_contents[0].name);
1010 EXPECT_FALSE(reoffer_contents[1].rejected);
1011 EXPECT_EQ(second_type_, reoffer_contents[1].media_description()->type());
1012 std::string second_mid = reoffer_contents[1].name;
1013 EXPECT_NE(first_mid, second_mid);
1014
1015 // Note: Cannot actually set the reoffer since the callee is in the signaling
1016 // state 'have-remote-offer'.
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 not rejected in the current
1021// local description.
1022TEST_P(RecycleMediaSectionTest, PendingRemoteRejectedAndNotRejectedLocal) {
1023 auto caller = CreatePeerConnection();
1024 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
1025 auto callee = CreatePeerConnection();
1026
1027 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
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
Steve Antondcc3c022017-12-22 16:02:54 -08001056// Test all combinations of audio and video as the first and second media type
1057// for the media section. This is needed for full test coverage because
1058// MediaSession has separate functions for processing audio and video media
1059// sections.
Mirko Bonadeic84f6612019-01-31 12:20:57 +01001060INSTANTIATE_TEST_SUITE_P(
Steve Antondcc3c022017-12-22 16:02:54 -08001061 PeerConnectionJsepTest,
1062 RecycleMediaSectionTest,
1063 Combine(Values(cricket::MEDIA_TYPE_AUDIO, cricket::MEDIA_TYPE_VIDEO),
1064 Values(cricket::MEDIA_TYPE_AUDIO, cricket::MEDIA_TYPE_VIDEO)));
1065
Steve Antonfa2260d2017-12-28 16:38:23 -08001066// Test that a new data channel section will not reuse a recycleable audio or
1067// video media section. Additionally, tests that the new section is added to the
1068// end of the session description.
1069TEST_F(PeerConnectionJsepTest, DataChannelDoesNotRecycleMediaSection) {
1070 auto caller = CreatePeerConnection();
1071 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1072 auto callee = CreatePeerConnection();
1073
1074 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1075
Harald Alvestrand6060df52020-08-11 09:54:02 +02001076 transceiver->StopInternal();
Steve Antonfa2260d2017-12-28 16:38:23 -08001077
1078 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1079
1080 caller->CreateDataChannel("dc");
1081
1082 auto offer = caller->CreateOffer();
1083 auto offer_contents = offer->description()->contents();
1084 ASSERT_EQ(2u, offer_contents.size());
1085 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO,
1086 offer_contents[0].media_description()->type());
1087 EXPECT_EQ(cricket::MEDIA_TYPE_DATA,
1088 offer_contents[1].media_description()->type());
1089
1090 ASSERT_TRUE(
1091 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
1092 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1093
1094 auto answer = callee->CreateAnswer();
1095 auto answer_contents = answer->description()->contents();
1096 ASSERT_EQ(2u, answer_contents.size());
1097 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO,
1098 answer_contents[0].media_description()->type());
1099 EXPECT_EQ(cricket::MEDIA_TYPE_DATA,
1100 answer_contents[1].media_description()->type());
1101}
1102
1103// Test that if a new track is added to an existing session that has a data,
1104// the new section comes at the end of the new offer, after the existing data
1105// section.
1106TEST_F(PeerConnectionJsepTest, AudioTrackAddedAfterDataSectionInReoffer) {
1107 auto caller = CreatePeerConnection();
1108 caller->CreateDataChannel("dc");
1109 auto callee = CreatePeerConnection();
1110
1111 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1112
1113 caller->AddAudioTrack("a");
1114
1115 auto offer = caller->CreateOffer();
1116 auto contents = offer->description()->contents();
1117 ASSERT_EQ(2u, contents.size());
1118 EXPECT_EQ(cricket::MEDIA_TYPE_DATA, contents[0].media_description()->type());
1119 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, contents[1].media_description()->type());
1120}
1121
Steve Antondcc3c022017-12-22 16:02:54 -08001122// Tests for MID properties.
1123
1124static void RenameSection(size_t mline_index,
1125 const std::string& new_mid,
1126 SessionDescriptionInterface* sdesc) {
1127 cricket::SessionDescription* desc = sdesc->description();
1128 std::string old_mid = desc->contents()[mline_index].name;
1129 desc->contents()[mline_index].name = new_mid;
1130 desc->transport_infos()[mline_index].content_name = new_mid;
1131 const cricket::ContentGroup* bundle =
1132 desc->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1133 if (bundle) {
1134 cricket::ContentGroup new_bundle = *bundle;
1135 if (new_bundle.RemoveContentName(old_mid)) {
1136 new_bundle.AddContentName(new_mid);
1137 }
1138 desc->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1139 desc->AddGroup(new_bundle);
1140 }
1141}
1142
1143// Test that two PeerConnections can have a successful offer/answer exchange if
1144// the MIDs are changed from the defaults.
1145TEST_F(PeerConnectionJsepTest, OfferAnswerWithChangedMids) {
1146 constexpr char kFirstMid[] = "nondefaultmid";
1147 constexpr char kSecondMid[] = "randommid";
1148
1149 auto caller = CreatePeerConnection();
1150 caller->AddAudioTrack("a");
1151 caller->AddAudioTrack("b");
1152 auto callee = CreatePeerConnection();
1153
1154 auto offer = caller->CreateOffer();
1155 RenameSection(0, kFirstMid, offer.get());
1156 RenameSection(1, kSecondMid, offer.get());
1157
1158 ASSERT_TRUE(
1159 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
1160 auto caller_transceivers = caller->pc()->GetTransceivers();
1161 EXPECT_EQ(kFirstMid, caller_transceivers[0]->mid());
1162 EXPECT_EQ(kSecondMid, caller_transceivers[1]->mid());
1163
1164 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1165 auto callee_transceivers = callee->pc()->GetTransceivers();
1166 EXPECT_EQ(kFirstMid, callee_transceivers[0]->mid());
1167 EXPECT_EQ(kSecondMid, callee_transceivers[1]->mid());
1168
1169 auto answer = callee->CreateAnswer();
1170 auto answer_contents = answer->description()->contents();
1171 EXPECT_EQ(kFirstMid, answer_contents[0].name);
1172 EXPECT_EQ(kSecondMid, answer_contents[1].name);
1173
1174 ASSERT_TRUE(
1175 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
1176 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
1177}
1178
1179// Test that CreateOffer will generate a MID that is not already used if the
1180// default it would have picked is already taken. This is tested by using a
1181// third PeerConnection to determine what the default would be for the second
1182// media section then setting that as the first media section's MID.
1183TEST_F(PeerConnectionJsepTest, CreateOfferGeneratesUniqueMidIfAlreadyTaken) {
1184 // First, find what the default MID is for the second media section.
1185 auto pc = CreatePeerConnection();
1186 pc->AddAudioTrack("a");
1187 pc->AddAudioTrack("b");
1188 auto default_offer = pc->CreateOffer();
1189 std::string default_second_mid =
1190 default_offer->description()->contents()[1].name;
1191
1192 // Now, do an offer/answer with one track which has the MID set to the default
1193 // second MID.
1194 auto caller = CreatePeerConnection();
1195 caller->AddAudioTrack("a");
1196 auto callee = CreatePeerConnection();
1197
1198 auto offer = caller->CreateOffer();
1199 RenameSection(0, default_second_mid, offer.get());
1200
1201 ASSERT_TRUE(
1202 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
1203 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1204 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1205
1206 // Add a second track and ensure that the MID is different.
1207 caller->AddAudioTrack("b");
1208
1209 auto reoffer = caller->CreateOffer();
1210 auto reoffer_contents = reoffer->description()->contents();
1211 EXPECT_EQ(default_second_mid, reoffer_contents[0].name);
1212 EXPECT_NE(reoffer_contents[0].name, reoffer_contents[1].name);
1213}
1214
Steve Antonfa2260d2017-12-28 16:38:23 -08001215// Test that if an audio or video section has the default data section MID, then
1216// CreateOffer will generate a unique MID for the newly added data section.
1217TEST_F(PeerConnectionJsepTest,
1218 CreateOfferGeneratesUniqueMidForDataSectionIfAlreadyTaken) {
1219 // First, find what the default MID is for the data channel.
1220 auto pc = CreatePeerConnection();
1221 pc->CreateDataChannel("dc");
1222 auto default_offer = pc->CreateOffer();
1223 std::string default_data_mid =
1224 default_offer->description()->contents()[0].name;
1225
1226 // Now do an offer/answer with one audio track which has a MID set to the
1227 // default data MID.
1228 auto caller = CreatePeerConnection();
1229 caller->AddAudioTrack("a");
1230 auto callee = CreatePeerConnection();
1231
1232 auto offer = caller->CreateOffer();
1233 RenameSection(0, default_data_mid, offer.get());
1234
1235 ASSERT_TRUE(
1236 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
1237 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1238 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1239
1240 // Add a data channel and ensure that the MID is different.
1241 caller->CreateDataChannel("dc");
1242
1243 auto reoffer = caller->CreateOffer();
1244 auto reoffer_contents = reoffer->description()->contents();
1245 EXPECT_EQ(default_data_mid, reoffer_contents[0].name);
1246 EXPECT_NE(reoffer_contents[0].name, reoffer_contents[1].name);
1247}
1248
Steve Antondcc3c022017-12-22 16:02:54 -08001249// Test that a reoffer initiated by the callee adds a new track to the caller.
1250TEST_F(PeerConnectionJsepTest, CalleeDoesReoffer) {
1251 auto caller = CreatePeerConnection();
1252 caller->AddAudioTrack("a");
1253 auto callee = CreatePeerConnection();
1254 callee->AddAudioTrack("a");
1255 callee->AddVideoTrack("v");
1256
1257 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1258
1259 EXPECT_EQ(1u, caller->pc()->GetTransceivers().size());
1260 EXPECT_EQ(2u, callee->pc()->GetTransceivers().size());
1261
1262 ASSERT_TRUE(callee->ExchangeOfferAnswerWith(caller.get()));
1263
1264 EXPECT_EQ(2u, caller->pc()->GetTransceivers().size());
1265 EXPECT_EQ(2u, callee->pc()->GetTransceivers().size());
1266}
1267
Steve Anton02ee47c2018-01-10 16:26:06 -08001268// Tests for MSID properties.
1269
1270// Test that adding a track with AddTrack results in an offer that signals the
1271// track's ID.
1272TEST_F(PeerConnectionJsepTest, AddingTrackWithAddTrackSpecifiesTrackId) {
1273 const std::string kTrackId = "audio_track";
1274
1275 auto caller = CreatePeerConnection();
1276 caller->AddAudioTrack(kTrackId);
1277
1278 auto offer = caller->CreateOffer();
1279 auto contents = offer->description()->contents();
1280 ASSERT_EQ(1u, contents.size());
1281 auto streams = contents[0].media_description()->streams();
1282 ASSERT_EQ(1u, streams.size());
1283 EXPECT_EQ(kTrackId, streams[0].id);
1284}
1285
1286// Test that adding a track by calling AddTransceiver then SetTrack results in
1287// an offer that does not signal the track's ID and signals a random ID.
1288TEST_F(PeerConnectionJsepTest,
1289 AddingTrackWithAddTransceiverSpecifiesRandomTrackId) {
1290 const std::string kTrackId = "audio_track";
1291
1292 auto caller = CreatePeerConnection();
1293 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1294 transceiver->sender()->SetTrack(caller->CreateAudioTrack(kTrackId));
1295
1296 auto offer = caller->CreateOffer();
1297 auto contents = offer->description()->contents();
1298 ASSERT_EQ(1u, contents.size());
1299 auto streams = contents[0].media_description()->streams();
1300 ASSERT_EQ(1u, streams.size());
1301 EXPECT_NE(kTrackId, streams[0].id);
1302}
1303
Steve Anton5f94aa22018-02-01 10:58:30 -08001304// Test that if the transceiver is recvonly or inactive, then no MSID
1305// information is included in the offer.
1306TEST_F(PeerConnectionJsepTest, NoMsidInOfferIfTransceiverDirectionHasNoSend) {
1307 auto caller = CreatePeerConnection();
1308
1309 RtpTransceiverInit init_recvonly;
1310 init_recvonly.direction = RtpTransceiverDirection::kRecvOnly;
1311 ASSERT_TRUE(caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init_recvonly));
1312
1313 RtpTransceiverInit init_inactive;
1314 init_inactive.direction = RtpTransceiverDirection::kInactive;
1315 ASSERT_TRUE(caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init_inactive));
1316
1317 auto offer = caller->CreateOffer();
1318 auto contents = offer->description()->contents();
1319 ASSERT_EQ(2u, contents.size());
1320 // MSID is specified in the first stream, so no streams means no MSID.
1321 EXPECT_EQ(0u, contents[0].media_description()->streams().size());
1322 EXPECT_EQ(0u, contents[1].media_description()->streams().size());
1323}
1324
1325// Test that if an answer negotiates transceiver directions of recvonly or
1326// inactive, then no MSID information is included in the answer.
1327TEST_F(PeerConnectionJsepTest, NoMsidInAnswerIfNoRespondingTracks) {
1328 auto caller = CreatePeerConnection();
1329 auto callee = CreatePeerConnection();
1330
1331 // recvonly transceiver will get negotiated to inactive since the callee has
1332 // no tracks to send in response.
1333 RtpTransceiverInit init_recvonly;
1334 init_recvonly.direction = RtpTransceiverDirection::kRecvOnly;
1335 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init_recvonly);
1336
1337 // sendrecv transceiver will get negotiated to recvonly since the callee has
1338 // no tracks to send in response.
1339 RtpTransceiverInit init_sendrecv;
1340 init_sendrecv.direction = RtpTransceiverDirection::kSendRecv;
1341 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init_sendrecv);
1342
1343 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1344
1345 auto answer = callee->CreateAnswer();
1346 auto contents = answer->description()->contents();
1347 ASSERT_EQ(2u, contents.size());
1348 // MSID is specified in the first stream, so no streams means no MSID.
1349 EXPECT_EQ(0u, contents[0].media_description()->streams().size());
1350 EXPECT_EQ(0u, contents[1].media_description()->streams().size());
1351}
1352
1353// Test that the MSID is included even if the transceiver direction has changed
1354// to inactive if the transceiver had previously sent media.
1355TEST_F(PeerConnectionJsepTest, IncludeMsidEvenIfDirectionHasChanged) {
1356 auto caller = CreatePeerConnection();
1357 caller->AddAudioTrack("audio");
1358 auto callee = CreatePeerConnection();
1359 callee->AddAudioTrack("audio");
1360
1361 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1362
Harald Alvestrand6060df52020-08-11 09:54:02 +02001363 caller->pc()->GetTransceivers()[0]->SetDirectionWithError(
Steve Anton5f94aa22018-02-01 10:58:30 -08001364 RtpTransceiverDirection::kInactive);
1365
1366 // The transceiver direction on both sides will turn to inactive.
1367 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1368
1369 auto* offer = callee->pc()->remote_description();
1370 auto offer_contents = offer->description()->contents();
1371 ASSERT_EQ(1u, offer_contents.size());
1372 // MSID is specified in the first stream. If it is present, assume that MSID
1373 // is there.
1374 EXPECT_EQ(1u, offer_contents[0].media_description()->streams().size());
1375
1376 auto* answer = caller->pc()->remote_description();
1377 auto answer_contents = answer->description()->contents();
1378 ASSERT_EQ(1u, answer_contents.size());
1379 EXPECT_EQ(1u, answer_contents[0].media_description()->streams().size());
1380}
1381
1382// Test that stopping a RtpTransceiver will cause future offers to not include
1383// any MSID information for that section.
1384TEST_F(PeerConnectionJsepTest, RemoveMsidIfTransceiverStopped) {
1385 auto caller = CreatePeerConnection();
1386 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1387 auto callee = CreatePeerConnection();
1388
1389 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1390
Harald Alvestrand6060df52020-08-11 09:54:02 +02001391 transceiver->StopInternal();
Steve Anton5f94aa22018-02-01 10:58:30 -08001392
1393 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1394
1395 auto* offer = callee->pc()->remote_description();
1396 auto offer_contents = offer->description()->contents();
1397 ASSERT_EQ(1u, offer_contents.size());
1398 // MSID is specified in the first stream, so no streams means no MSID.
1399 EXPECT_EQ(0u, offer_contents[0].media_description()->streams().size());
1400}
1401
Steve Anton02ee47c2018-01-10 16:26:06 -08001402// Test that the callee RtpReceiver created by a call to SetRemoteDescription
1403// has its ID set to the signaled track ID.
1404TEST_F(PeerConnectionJsepTest,
1405 RtpReceiverCreatedBySetRemoteDescriptionHasSignaledTrackId) {
1406 const std::string kTrackId = "audio_track";
1407
1408 auto caller = CreatePeerConnection();
1409 auto callee = CreatePeerConnection();
1410 caller->AddAudioTrack(kTrackId);
1411
1412 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1413
1414 ASSERT_EQ(1u, callee->pc()->GetReceivers().size());
1415 auto receiver = callee->pc()->GetReceivers()[0];
1416 EXPECT_EQ(kTrackId, receiver->id());
1417}
1418
1419// Test that if the callee RtpReceiver is reused by a call to
1420// SetRemoteDescription, its ID does not change.
1421TEST_F(PeerConnectionJsepTest,
1422 RtpReceiverCreatedBeforeSetRemoteDescriptionKeepsId) {
1423 const std::string kTrackId = "audio_track";
1424
1425 auto caller = CreatePeerConnection();
1426 auto callee = CreatePeerConnection();
1427 caller->AddAudioTrack(kTrackId);
1428 callee->AddAudioTrack("dummy_track");
1429
1430 ASSERT_EQ(1u, callee->pc()->GetReceivers().size());
1431 auto receiver = callee->pc()->GetReceivers()[0];
1432 std::string receiver_id = receiver->id();
1433
1434 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1435
1436 EXPECT_EQ(receiver_id, receiver->id());
1437}
1438
Steve Antonef65ef12018-01-10 17:15:20 -08001439// Test that setting a remote offer with one track that has no streams fires off
1440// the correct OnAddTrack event.
1441TEST_F(PeerConnectionJsepTest,
1442 SetRemoteOfferWithOneTrackNoStreamFiresOnAddTrack) {
1443 const std::string kTrackLabel = "audio_track";
1444
1445 auto caller = CreatePeerConnection();
1446 auto callee = CreatePeerConnection();
1447 ASSERT_TRUE(caller->AddAudioTrack(kTrackLabel));
1448
1449 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1450
Seth Hampson5b4f0752018-04-02 16:31:36 -07001451 const auto& track_events = callee->observer()->add_track_events_;
1452 ASSERT_EQ(1u, track_events.size());
1453 const auto& event = track_events[0];
1454 EXPECT_EQ(kTrackLabel, event.receiver->track()->id());
1455 EXPECT_EQ(0u, event.streams.size());
Steve Antonef65ef12018-01-10 17:15:20 -08001456}
1457
1458// Test that setting a remote offer with one track that has one stream fires off
1459// the correct OnAddTrack event.
1460TEST_F(PeerConnectionJsepTest,
1461 SetRemoteOfferWithOneTrackOneStreamFiresOnAddTrack) {
1462 const std::string kTrackLabel = "audio_track";
Seth Hampson845e8782018-03-02 11:34:10 -08001463 const std::string kStreamId = "audio_stream";
Steve Antonef65ef12018-01-10 17:15:20 -08001464
1465 auto caller = CreatePeerConnection();
1466 auto callee = CreatePeerConnection();
Seth Hampson845e8782018-03-02 11:34:10 -08001467 ASSERT_TRUE(caller->AddAudioTrack(kTrackLabel, {kStreamId}));
Steve Antonef65ef12018-01-10 17:15:20 -08001468
1469 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1470
1471 const auto& track_events = callee->observer()->add_track_events_;
1472 ASSERT_EQ(1u, track_events.size());
1473 const auto& event = track_events[0];
1474 ASSERT_EQ(1u, event.streams.size());
1475 auto stream = event.streams[0];
Seth Hampson13b8bad2018-03-13 16:05:28 -07001476 EXPECT_EQ(kStreamId, stream->id());
Steve Antonef65ef12018-01-10 17:15:20 -08001477 EXPECT_THAT(track_events[0].snapshotted_stream_tracks.at(stream),
1478 ElementsAre(event.receiver->track()));
1479 EXPECT_EQ(event.receiver->streams(), track_events[0].streams);
1480}
1481
1482// Test that setting a remote offer with two tracks that share the same stream
1483// fires off two OnAddTrack events, both with the same stream that has both
1484// tracks present at the time of firing. This is to ensure that track events are
1485// not fired until SetRemoteDescription has finished processing all the media
1486// sections.
1487TEST_F(PeerConnectionJsepTest,
1488 SetRemoteOfferWithTwoTracksSameStreamFiresOnAddTrack) {
1489 const std::string kTrack1Label = "audio_track1";
1490 const std::string kTrack2Label = "audio_track2";
Seth Hampson845e8782018-03-02 11:34:10 -08001491 const std::string kSharedStreamId = "stream";
Steve Antonef65ef12018-01-10 17:15:20 -08001492
1493 auto caller = CreatePeerConnection();
1494 auto callee = CreatePeerConnection();
Seth Hampson845e8782018-03-02 11:34:10 -08001495 ASSERT_TRUE(caller->AddAudioTrack(kTrack1Label, {kSharedStreamId}));
1496 ASSERT_TRUE(caller->AddAudioTrack(kTrack2Label, {kSharedStreamId}));
Steve Antonef65ef12018-01-10 17:15:20 -08001497
1498 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1499
1500 const auto& track_events = callee->observer()->add_track_events_;
1501 ASSERT_EQ(2u, track_events.size());
1502 const auto& event1 = track_events[0];
1503 const auto& event2 = track_events[1];
1504 ASSERT_EQ(1u, event1.streams.size());
1505 auto stream = event1.streams[0];
1506 ASSERT_THAT(event2.streams, ElementsAre(stream));
1507 auto track1 = event1.receiver->track();
1508 auto track2 = event2.receiver->track();
1509 EXPECT_THAT(event1.snapshotted_stream_tracks.at(stream),
1510 UnorderedElementsAre(track1, track2));
1511 EXPECT_THAT(event2.snapshotted_stream_tracks.at(stream),
1512 UnorderedElementsAre(track1, track2));
1513}
1514
Seth Hampson5b4f0752018-04-02 16:31:36 -07001515// Test that setting a remote offer with one track that has two streams fires
1516// off the correct OnAddTrack event.
1517TEST_F(PeerConnectionJsepTest,
1518 SetRemoteOfferWithOneTrackTwoStreamFiresOnAddTrack) {
1519 const std::string kTrackLabel = "audio_track";
1520 const std::string kStreamId1 = "audio_stream1";
1521 const std::string kStreamId2 = "audio_stream2";
1522
1523 auto caller = CreatePeerConnection();
1524 auto callee = CreatePeerConnection();
1525 ASSERT_TRUE(caller->AddAudioTrack(kTrackLabel, {kStreamId1, kStreamId2}));
1526
1527 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1528
1529 const auto& track_events = callee->observer()->add_track_events_;
1530 ASSERT_EQ(1u, track_events.size());
1531 const auto& event = track_events[0];
1532 ASSERT_EQ(2u, event.streams.size());
1533 EXPECT_EQ(kStreamId1, event.streams[0]->id());
1534 EXPECT_EQ(kStreamId2, event.streams[1]->id());
1535}
Steve Antonef65ef12018-01-10 17:15:20 -08001536
Steve Anton54b84072018-02-20 15:19:52 -08001537// Test that if an RtpTransceiver with a current_direction set is stopped, then
1538// current_direction is changed to null.
1539TEST_F(PeerConnectionJsepTest, CurrentDirectionResetWhenRtpTransceiverStopped) {
1540 auto caller = CreatePeerConnection();
1541 auto callee = CreatePeerConnection();
1542
1543 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1544
1545 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1546
1547 ASSERT_TRUE(transceiver->current_direction());
Harald Alvestrand6060df52020-08-11 09:54:02 +02001548 transceiver->StopInternal();
1549 EXPECT_EQ(transceiver->current_direction(),
1550 RtpTransceiverDirection::kStopped);
Steve Anton54b84072018-02-20 15:19:52 -08001551}
1552
Steve Antonba42e992018-04-09 14:10:01 -07001553// Test that you can't set an answer on a PeerConnection before setting the
1554// offer.
Harald Alvestrand5081c0c2018-03-09 15:18:03 +01001555TEST_F(PeerConnectionJsepTest, AnswerBeforeOfferFails) {
1556 auto caller = CreatePeerConnection();
1557 auto callee = CreatePeerConnection();
Harald Alvestrand5081c0c2018-03-09 15:18:03 +01001558 caller->AddAudioTrack("audio");
Steve Antonba42e992018-04-09 14:10:01 -07001559
1560 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1561
1562 RTCError error;
1563 ASSERT_FALSE(caller->SetRemoteDescription(callee->CreateAnswer(), &error));
1564 EXPECT_EQ(RTCErrorType::INVALID_STATE, error.type());
1565}
1566
1567// Test that a Unified Plan PeerConnection fails to set a Plan B offer if it has
1568// two video tracks.
1569TEST_F(PeerConnectionJsepTest, TwoVideoPlanBToUnifiedPlanFails) {
1570 RTCConfiguration config_planb;
1571 config_planb.sdp_semantics = SdpSemantics::kPlanB;
1572 auto caller = CreatePeerConnection(config_planb);
1573 auto callee = CreatePeerConnection();
1574 caller->AddVideoTrack("video1");
1575 caller->AddVideoTrack("video2");
1576
1577 RTCError error;
1578 ASSERT_FALSE(callee->SetRemoteDescription(caller->CreateOffer(), &error));
1579 EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, error.type());
1580}
1581
1582// Test that a Unified Plan PeerConnection fails to set a Plan B answer if it
1583// has two video tracks.
1584TEST_F(PeerConnectionJsepTest, OneVideoUnifiedPlanToTwoVideoPlanBFails) {
1585 auto caller = CreatePeerConnection();
1586 RTCConfiguration config_planb;
1587 config_planb.sdp_semantics = SdpSemantics::kPlanB;
1588 auto callee = CreatePeerConnection(config_planb);
1589 caller->AddVideoTrack("video");
1590 callee->AddVideoTrack("video1");
1591 callee->AddVideoTrack("video2");
1592
1593 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1594
1595 RTCError error;
1596 ASSERT_FALSE(caller->SetRemoteDescription(caller->CreateAnswer(), &error));
1597 EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, error.type());
Harald Alvestrand5081c0c2018-03-09 15:18:03 +01001598}
1599
Steve Anton06817cd2018-12-18 15:55:30 -08001600// Removes the RTP header extension associated with the given URI from the media
1601// description.
1602static void RemoveRtpHeaderExtensionByUri(
1603 MediaContentDescription* media_description,
1604 absl::string_view uri) {
1605 std::vector<RtpExtension> header_extensions =
1606 media_description->rtp_header_extensions();
1607 header_extensions.erase(std::remove_if(
1608 header_extensions.begin(), header_extensions.end(),
1609 [uri](const RtpExtension& extension) { return extension.uri == uri; }));
1610 media_description->set_rtp_header_extensions(header_extensions);
1611}
1612
1613// Transforms a session description to emulate a legacy endpoint which does not
1614// support a=mid, BUNDLE, and the MID header extension.
1615static void ClearMids(SessionDescriptionInterface* sdesc) {
1616 cricket::SessionDescription* desc = sdesc->description();
1617 desc->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1618 cricket::ContentInfo* audio_content = cricket::GetFirstAudioContent(desc);
1619 if (audio_content) {
1620 desc->GetTransportInfoByName(audio_content->name)->content_name = "";
1621 audio_content->name = "";
1622 RemoveRtpHeaderExtensionByUri(audio_content->media_description(),
1623 RtpExtension::kMidUri);
1624 }
1625 cricket::ContentInfo* video_content = cricket::GetFirstVideoContent(desc);
1626 if (video_content) {
1627 desc->GetTransportInfoByName(video_content->name)->content_name = "";
1628 video_content->name = "";
1629 RemoveRtpHeaderExtensionByUri(video_content->media_description(),
1630 RtpExtension::kMidUri);
1631 }
1632}
1633
1634// Test that negotiation works with legacy endpoints which do not support a=mid.
1635TEST_F(PeerConnectionJsepTest, LegacyNoMidAudioOnlyOffer) {
1636 auto caller = CreatePeerConnection();
1637 caller->AddAudioTrack("audio");
1638 auto callee = CreatePeerConnection();
1639 callee->AddAudioTrack("audio");
1640
1641 auto offer = caller->CreateOffer();
1642 ClearMids(offer.get());
1643
1644 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1645 EXPECT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1646}
1647TEST_F(PeerConnectionJsepTest, LegacyNoMidAudioVideoOffer) {
1648 auto caller = CreatePeerConnection();
1649 caller->AddAudioTrack("audio");
1650 caller->AddVideoTrack("video");
1651 auto callee = CreatePeerConnection();
1652 callee->AddAudioTrack("audio");
1653 callee->AddVideoTrack("video");
1654
1655 auto offer = caller->CreateOffer();
1656 ClearMids(offer.get());
1657
1658 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1659 EXPECT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1660}
1661TEST_F(PeerConnectionJsepTest, LegacyNoMidAudioOnlyAnswer) {
1662 auto caller = CreatePeerConnection();
1663 caller->AddAudioTrack("audio");
1664 auto callee = CreatePeerConnection();
1665 callee->AddAudioTrack("audio");
1666
1667 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1668
1669 auto answer = callee->CreateAnswer();
1670 ClearMids(answer.get());
1671
1672 EXPECT_TRUE(caller->SetRemoteDescription(std::move(answer)));
1673}
1674TEST_F(PeerConnectionJsepTest, LegacyNoMidAudioVideoAnswer) {
1675 auto caller = CreatePeerConnection();
1676 caller->AddAudioTrack("audio");
1677 caller->AddVideoTrack("video");
1678 auto callee = CreatePeerConnection();
1679 callee->AddAudioTrack("audio");
1680 callee->AddVideoTrack("video");
1681
1682 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1683
1684 auto answer = callee->CreateAnswer();
1685 ClearMids(answer.get());
1686
1687 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
1688}
1689
Steve Antond7180cc2019-02-07 10:44:53 -08001690// Test that negotiation works with legacy endpoints which do not support a=mid
1691// when setting two remote descriptions without setting a local description in
1692// between.
1693TEST_F(PeerConnectionJsepTest, LegacyNoMidTwoRemoteOffers) {
1694 auto caller = CreatePeerConnection();
1695 caller->AddAudioTrack("audio");
1696 auto callee = CreatePeerConnection();
1697 callee->AddAudioTrack("audio");
1698
1699 auto offer = caller->CreateOffer();
1700 ClearMids(offer.get());
1701
1702 ASSERT_TRUE(
1703 callee->SetRemoteDescription(CloneSessionDescription(offer.get())));
1704 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1705 EXPECT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1706}
1707
Steve Antonceac0152018-12-19 11:32:20 -08001708// Test that SetLocalDescription fails if a=mid lines are missing.
1709TEST_F(PeerConnectionJsepTest, SetLocalDescriptionFailsMissingMid) {
1710 auto caller = CreatePeerConnection();
1711 caller->AddAudioTrack("audio");
1712
1713 auto offer = caller->CreateOffer();
1714 ClearMids(offer.get());
1715
1716 std::string error;
1717 ASSERT_FALSE(caller->SetLocalDescription(std::move(offer), &error));
1718 EXPECT_EQ(
1719 "Failed to set local offer sdp: A media section is missing a MID "
1720 "attribute.",
1721 error);
1722}
1723
Eldar Rello5ab79e62019-10-09 18:29:44 +03001724TEST_F(PeerConnectionJsepTest, RollbackSupportedInUnifiedPlan) {
1725 RTCConfiguration config;
1726 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
1727 config.enable_implicit_rollback = true;
1728 auto caller = CreatePeerConnection(config);
1729 auto callee = CreatePeerConnection(config);
1730 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
1731 EXPECT_TRUE(caller->SetLocalDescription(caller->CreateRollback()));
1732 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
1733 EXPECT_TRUE(caller->SetRemoteDescription(caller->CreateRollback()));
1734 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
1735 EXPECT_TRUE(caller->SetRemoteDescription(callee->CreateOffer()));
1736}
1737
1738TEST_F(PeerConnectionJsepTest, RollbackNotSupportedInPlanB) {
1739 RTCConfiguration config;
1740 config.sdp_semantics = SdpSemantics::kPlanB;
1741 config.enable_implicit_rollback = true;
1742 auto caller = CreatePeerConnection(config);
1743 auto callee = CreatePeerConnection(config);
1744 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
1745 EXPECT_FALSE(caller->SetLocalDescription(caller->CreateRollback()));
1746 EXPECT_FALSE(caller->SetRemoteDescription(caller->CreateRollback()));
1747 EXPECT_FALSE(caller->SetRemoteDescription(callee->CreateOffer()));
1748}
1749
1750TEST_F(PeerConnectionJsepTest, RollbackFailsInStableState) {
1751 auto caller = CreatePeerConnection();
1752 EXPECT_FALSE(caller->SetLocalDescription(caller->CreateRollback()));
1753 EXPECT_FALSE(caller->SetRemoteDescription(caller->CreateRollback()));
1754}
1755
1756TEST_F(PeerConnectionJsepTest, RollbackToStableStateAndClearLocalOffer) {
1757 auto caller = CreatePeerConnection();
1758 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
1759 EXPECT_TRUE(caller->SetLocalDescription(caller->CreateRollback()));
1760 EXPECT_EQ(caller->signaling_state(), PeerConnectionInterface::kStable);
1761 EXPECT_EQ(caller->pc()->pending_local_description(), nullptr);
1762
1763 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
1764 EXPECT_TRUE(caller->SetRemoteDescription(caller->CreateRollback()));
1765 EXPECT_EQ(caller->signaling_state(), PeerConnectionInterface::kStable);
1766 EXPECT_EQ(caller->pc()->pending_local_description(), nullptr);
1767}
1768
1769TEST_F(PeerConnectionJsepTest, RollbackToStableStateAndClearRemoteOffer) {
1770 auto caller = CreatePeerConnection();
1771 auto callee = CreatePeerConnection();
1772 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1773 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
1774 EXPECT_EQ(callee->signaling_state(), PeerConnectionInterface::kStable);
1775 EXPECT_EQ(callee->pc()->pending_remote_description(), nullptr);
1776
1777 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1778 EXPECT_TRUE(callee->SetLocalDescription(caller->CreateRollback()));
1779 EXPECT_EQ(callee->signaling_state(), PeerConnectionInterface::kStable);
1780 EXPECT_EQ(callee->pc()->pending_remote_description(), nullptr);
1781}
1782
Eldar Relloead0ec92019-10-21 23:01:31 +03001783TEST_F(PeerConnectionJsepTest, RollbackImplicitly) {
Eldar Rello5ab79e62019-10-09 18:29:44 +03001784 RTCConfiguration config;
1785 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
1786 config.enable_implicit_rollback = true;
1787 auto caller = CreatePeerConnection(config);
1788 auto callee = CreatePeerConnection(config);
1789 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
1790 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1791 EXPECT_EQ(callee->signaling_state(),
1792 PeerConnectionInterface::kHaveRemoteOffer);
Eldar Relloead0ec92019-10-21 23:01:31 +03001793 EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal());
Henrik Boströme574a312020-08-25 10:20:11 +02001794 EXPECT_FALSE(callee->observer()->legacy_renegotiation_needed());
1795 EXPECT_FALSE(callee->observer()->has_negotiation_needed_event());
Eldar Rello5ab79e62019-10-09 18:29:44 +03001796}
1797
Eldar Relloead0ec92019-10-21 23:01:31 +03001798TEST_F(PeerConnectionJsepTest, RollbackImplicitlyNegotatiationNotNeeded) {
1799 RTCConfiguration config;
1800 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
1801 config.enable_implicit_rollback = true;
1802 auto caller = CreatePeerConnection(config);
1803 auto callee = CreatePeerConnection(config);
1804 caller->AddAudioTrack("a");
1805 callee->AddAudioTrack("b");
1806 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
Henrik Boströme574a312020-08-25 10:20:11 +02001807 callee->observer()->clear_legacy_renegotiation_needed();
1808 callee->observer()->clear_latest_negotiation_needed_event();
Eldar Relloead0ec92019-10-21 23:01:31 +03001809 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1810 EXPECT_EQ(callee->signaling_state(),
1811 PeerConnectionInterface::kHaveRemoteOffer);
1812 EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal());
1813 // No negotiation needed as track got attached in the answer.
Henrik Boströme574a312020-08-25 10:20:11 +02001814 EXPECT_FALSE(callee->observer()->legacy_renegotiation_needed());
1815 EXPECT_FALSE(callee->observer()->has_negotiation_needed_event());
Eldar Relloead0ec92019-10-21 23:01:31 +03001816 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 0u);
1817}
1818
1819TEST_F(PeerConnectionJsepTest, RollbackImplicitlyAndNegotiationNeeded) {
1820 RTCConfiguration config;
1821 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
1822 config.enable_implicit_rollback = true;
1823 auto caller = CreatePeerConnection(config);
1824 auto callee = CreatePeerConnection(config);
1825 callee->AddAudioTrack("a");
1826 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
Henrik Boströme574a312020-08-25 10:20:11 +02001827 callee->observer()->clear_legacy_renegotiation_needed();
1828 callee->observer()->clear_latest_negotiation_needed_event();
Eldar Relloead0ec92019-10-21 23:01:31 +03001829 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1830 EXPECT_EQ(callee->signaling_state(),
1831 PeerConnectionInterface::kHaveRemoteOffer);
Henrik Boströme574a312020-08-25 10:20:11 +02001832 EXPECT_FALSE(callee->observer()->legacy_renegotiation_needed());
1833 EXPECT_FALSE(callee->observer()->has_negotiation_needed_event());
Eldar Relloead0ec92019-10-21 23:01:31 +03001834 EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal());
Henrik Boströme574a312020-08-25 10:20:11 +02001835 EXPECT_TRUE(callee->observer()->legacy_renegotiation_needed());
1836 EXPECT_TRUE(callee->observer()->has_negotiation_needed_event());
Eldar Relloead0ec92019-10-21 23:01:31 +03001837 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 0u);
1838}
1839
1840TEST_F(PeerConnectionJsepTest, AttemptToRollbackImplicitly) {
Eldar Rello5ab79e62019-10-09 18:29:44 +03001841 RTCConfiguration config;
1842 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
1843 config.enable_implicit_rollback = true;
1844 auto caller = CreatePeerConnection(config);
1845 auto callee = CreatePeerConnection(config);
1846 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
1847 EXPECT_FALSE(callee->SetRemoteDescription(
1848 CreateSessionDescription(SdpType::kOffer, "invalid sdp")));
1849 EXPECT_EQ(callee->signaling_state(),
1850 PeerConnectionInterface::kHaveLocalOffer);
1851}
1852
1853TEST_F(PeerConnectionJsepTest, RollbackRemovesTransceiver) {
1854 auto caller = CreatePeerConnection();
1855 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1856 auto callee = CreatePeerConnection();
1857 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
Eldar Relloead0ec92019-10-21 23:01:31 +03001858 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
Eldar Rello5ab79e62019-10-09 18:29:44 +03001859 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
Eldar Relloead0ec92019-10-21 23:01:31 +03001860 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 0u);
1861 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 1u);
Eldar Rello5ab79e62019-10-09 18:29:44 +03001862}
1863
1864TEST_F(PeerConnectionJsepTest, RollbackKeepsTransceiverAndClearsMid) {
1865 auto caller = CreatePeerConnection();
1866 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1867 auto callee = CreatePeerConnection();
1868 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1869 callee->AddAudioTrack("a");
Eldar Relloead0ec92019-10-21 23:01:31 +03001870 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
Eldar Rello5ab79e62019-10-09 18:29:44 +03001871 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
1872 // Transceiver can't be removed as track was added to it.
Eldar Relloead0ec92019-10-21 23:01:31 +03001873 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
Eldar Rello5ab79e62019-10-09 18:29:44 +03001874 // Mid got cleared to make it reusable.
1875 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), absl::nullopt);
1876 // Transceiver should be counted as addTrack-created after rollback.
1877 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
Eldar Relloead0ec92019-10-21 23:01:31 +03001878 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
1879 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 1u);
Eldar Rello5ab79e62019-10-09 18:29:44 +03001880}
1881
Eldar Rello353a7182019-11-25 18:49:44 +02001882TEST_F(PeerConnectionJsepTest,
1883 RollbackKeepsTransceiverAfterAddTrackEvenWhenTrackIsNulled) {
1884 auto caller = CreatePeerConnection();
1885 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1886 auto callee = CreatePeerConnection();
1887 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1888 callee->AddAudioTrack("a");
1889 callee->pc()->GetTransceivers()[0]->sender()->SetTrack(nullptr);
1890 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->sender()->track(), nullptr);
1891 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
1892 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
1893 // Transceiver can't be removed as track was added to it.
1894 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
1895 // Mid got cleared to make it reusable.
1896 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), absl::nullopt);
1897 // Transceiver should be counted as addTrack-created after rollback.
1898 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1899 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
1900 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 1u);
1901}
1902
Eldar Rello5ab79e62019-10-09 18:29:44 +03001903TEST_F(PeerConnectionJsepTest, RollbackRestoresMid) {
1904 auto caller = CreatePeerConnection();
1905 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1906 auto callee = CreatePeerConnection();
1907 callee->AddAudioTrack("a");
1908 auto offer = callee->CreateOffer();
1909 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
Eldar Relloead0ec92019-10-21 23:01:31 +03001910 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
Eldar Rello5ab79e62019-10-09 18:29:44 +03001911 EXPECT_NE(callee->pc()->GetTransceivers()[0]->mid(), absl::nullopt);
1912 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
1913 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), absl::nullopt);
1914 EXPECT_TRUE(callee->SetLocalDescription(std::move(offer)));
1915}
1916
1917TEST_F(PeerConnectionJsepTest, RollbackRestoresMidAndRemovesTransceiver) {
1918 auto callee = CreatePeerConnection();
1919 callee->AddVideoTrack("a");
1920 auto offer = callee->CreateOffer();
1921 auto caller = CreatePeerConnection();
1922 caller->AddAudioTrack("b");
1923 caller->AddVideoTrack("c");
1924 auto mid = callee->pc()->GetTransceivers()[0]->mid();
1925 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
Eldar Relloead0ec92019-10-21 23:01:31 +03001926 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 2u);
Eldar Rello5ab79e62019-10-09 18:29:44 +03001927 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
Eldar Relloead0ec92019-10-21 23:01:31 +03001928 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
Eldar Rello5ab79e62019-10-09 18:29:44 +03001929 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), mid);
1930 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->media_type(),
1931 cricket::MEDIA_TYPE_VIDEO);
1932 EXPECT_TRUE(callee->SetLocalDescription(std::move(offer)));
Eldar Relloead0ec92019-10-21 23:01:31 +03001933 EXPECT_EQ(callee->observer()->remove_track_events_.size(),
1934 callee->observer()->add_track_events_.size());
1935}
1936
1937TEST_F(PeerConnectionJsepTest, RollbackHasNoEffectOnStableTransceivers) {
1938 auto callee = CreatePeerConnection();
1939 callee->AddVideoTrack("a");
1940 auto caller = CreatePeerConnection();
1941 caller->AddAudioTrack("b");
1942 caller->AddVideoTrack("c");
1943 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1944 EXPECT_TRUE(
1945 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1946 // In stable don't add or remove anything.
Henrik Boströme574a312020-08-25 10:20:11 +02001947 callee->observer()->clear_legacy_renegotiation_needed();
1948 callee->observer()->clear_latest_negotiation_needed_event();
Eldar Relloead0ec92019-10-21 23:01:31 +03001949 size_t transceiver_count = callee->pc()->GetTransceivers().size();
1950 auto mid_0 = callee->pc()->GetTransceivers()[0]->mid();
1951 auto mid_1 = callee->pc()->GetTransceivers()[1]->mid();
1952 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1953 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
1954 EXPECT_EQ(callee->pc()->GetTransceivers().size(), transceiver_count);
1955 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), mid_0);
1956 EXPECT_EQ(callee->pc()->GetTransceivers()[1]->mid(), mid_1);
1957 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 0u);
Henrik Boströme574a312020-08-25 10:20:11 +02001958 EXPECT_FALSE(callee->observer()->legacy_renegotiation_needed());
1959 EXPECT_FALSE(callee->observer()->has_negotiation_needed_event());
Eldar Rello5ab79e62019-10-09 18:29:44 +03001960}
1961
1962TEST_F(PeerConnectionJsepTest, ImplicitlyRollbackTransceiversWithSameMids) {
1963 RTCConfiguration config;
1964 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
1965 config.enable_implicit_rollback = true;
1966 auto caller = CreatePeerConnection(config);
1967 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
1968 auto callee = CreatePeerConnection(config);
1969 callee->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
1970 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
1971 auto initial_mid = callee->pc()->GetTransceivers()[0]->mid();
1972 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
Eldar Relloead0ec92019-10-21 23:01:31 +03001973 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 2u);
Eldar Rello5ab79e62019-10-09 18:29:44 +03001974 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), absl::nullopt);
1975 EXPECT_EQ(callee->pc()->GetTransceivers()[1]->mid(),
1976 caller->pc()->GetTransceivers()[0]->mid());
1977 EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal()); // Go to stable.
1978 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
1979 EXPECT_NE(callee->pc()->GetTransceivers()[0]->mid(), initial_mid);
1980}
1981
1982TEST_F(PeerConnectionJsepTest, RollbackToNegotiatedStableState) {
1983 RTCConfiguration config;
1984 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
1985 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
1986 auto caller = CreatePeerConnection(config);
1987 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1988 auto callee = CreatePeerConnection(config);
1989 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1990 EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal());
1991 caller->AddVideoTrack("a");
1992 callee->AddVideoTrack("b");
1993 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
Eldar Relloead0ec92019-10-21 23:01:31 +03001994 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 2u);
Eldar Rello5ab79e62019-10-09 18:29:44 +03001995 auto audio_transport =
1996 callee->pc()->GetTransceivers()[0]->sender()->dtls_transport();
1997 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
1998 callee->pc()->GetTransceivers()[1]->sender()->dtls_transport());
1999 EXPECT_NE(callee->pc()->GetTransceivers()[1]->sender()->dtls_transport(),
2000 nullptr);
2001 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
2002 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
2003 audio_transport); // Audio must remain working after rollback.
2004 EXPECT_EQ(callee->pc()->GetTransceivers()[1]->sender()->dtls_transport(),
2005 nullptr);
2006 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2007
2008 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
2009 audio_transport); // Audio transport is still the same.
2010}
2011
Eldar Rello353a7182019-11-25 18:49:44 +02002012TEST_F(PeerConnectionJsepTest, RollbackHasToDestroyTransport) {
2013 RTCConfiguration config;
2014 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
2015 config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
2016 auto pc = CreatePeerConnection(config);
2017 pc->AddAudioTrack("a");
2018 pc->AddVideoTrack("b");
2019 EXPECT_TRUE(pc->CreateOfferAndSetAsLocal());
2020 auto offer = pc->CreateOffer();
2021 EXPECT_EQ(pc->pc()->GetTransceivers().size(), 2u);
2022 auto audio_transport =
2023 pc->pc()->GetTransceivers()[0]->sender()->dtls_transport();
2024 EXPECT_EQ(pc->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
2025 pc->pc()->GetTransceivers()[1]->sender()->dtls_transport());
2026 EXPECT_NE(pc->pc()->GetTransceivers()[1]->sender()->dtls_transport(),
2027 nullptr);
2028 EXPECT_TRUE(pc->SetRemoteDescription(pc->CreateRollback()));
2029 EXPECT_TRUE(pc->SetLocalDescription(std::move(offer)));
2030 EXPECT_NE(pc->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
2031 nullptr);
2032 EXPECT_NE(pc->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
2033 audio_transport);
2034}
2035
Eldar Relloead0ec92019-10-21 23:01:31 +03002036TEST_F(PeerConnectionJsepTest, RollbackLocalDirectionChange) {
2037 auto caller = CreatePeerConnection();
2038 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
2039 auto callee = CreatePeerConnection();
2040 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2041 EXPECT_TRUE(
2042 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
2043 callee->AddAudioTrack("a");
Harald Alvestrand6060df52020-08-11 09:54:02 +02002044 callee->pc()->GetTransceivers()[0]->SetDirectionWithError(
Eldar Relloead0ec92019-10-21 23:01:31 +03002045 RtpTransceiverDirection::kSendOnly);
2046 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2047 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
2048 auto audio_transport =
2049 callee->pc()->GetTransceivers()[0]->receiver()->dtls_transport();
2050 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
2051 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->direction(),
2052 RtpTransceiverDirection::kSendOnly);
2053 // One way audio must remain working after rollback as local direction change
2054 // comes in effect after completing full negotiation round.
2055 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->receiver()->dtls_transport(),
2056 audio_transport);
2057}
2058
2059TEST_F(PeerConnectionJsepTest, RollbackRemoteDirectionChange) {
2060 auto caller = CreatePeerConnection();
2061 auto caller_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
2062 auto callee = CreatePeerConnection();
2063 callee->AddAudioTrack("a");
2064 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2065 EXPECT_TRUE(
2066 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
2067 // In stable make remote audio receive only.
Harald Alvestrand6060df52020-08-11 09:54:02 +02002068 caller_transceiver->SetDirectionWithError(RtpTransceiverDirection::kRecvOnly);
Eldar Relloead0ec92019-10-21 23:01:31 +03002069 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2070 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
2071 // The direction attribute is not modified by the offer.
2072 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->direction(),
2073 RtpTransceiverDirection::kSendRecv);
2074 auto audio_transport =
2075 callee->pc()->GetTransceivers()[0]->sender()->dtls_transport();
2076 EXPECT_EQ(callee->observer()->add_track_events_.size(), 1u);
2077 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 1u);
2078 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateRollback()));
2079 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 1u);
2080 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->direction(),
2081 RtpTransceiverDirection::kSendRecv);
2082 // One way audio must remain working after rollback.
2083 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->sender()->dtls_transport(),
2084 audio_transport);
2085 EXPECT_EQ(callee->observer()->remove_track_events_.size(), 1u);
2086}
2087
Eldar Rello5ab79e62019-10-09 18:29:44 +03002088TEST_F(PeerConnectionJsepTest, RollbackAfterMultipleSLD) {
2089 auto callee = CreatePeerConnection();
2090 callee->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
2091 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2092 callee->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2093 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
Henrik Boströme574a312020-08-25 10:20:11 +02002094 callee->observer()->clear_legacy_renegotiation_needed();
2095 callee->observer()->clear_latest_negotiation_needed_event();
Eldar Rello5ab79e62019-10-09 18:29:44 +03002096 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
Henrik Boströme574a312020-08-25 10:20:11 +02002097 EXPECT_TRUE(callee->observer()->legacy_renegotiation_needed());
2098 EXPECT_TRUE(callee->observer()->has_negotiation_needed_event());
Eldar Relloead0ec92019-10-21 23:01:31 +03002099 EXPECT_EQ(callee->pc()->GetTransceivers().size(), 2u);
Eldar Rello5ab79e62019-10-09 18:29:44 +03002100 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->mid(), absl::nullopt);
2101 EXPECT_EQ(callee->pc()->GetTransceivers()[1]->mid(), absl::nullopt);
2102}
2103
2104TEST_F(PeerConnectionJsepTest, NoRollbackNeeded) {
2105 auto caller = CreatePeerConnection();
2106 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
2107 auto callee = CreatePeerConnection();
2108 callee->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
2109 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
2110 EXPECT_TRUE(caller->CreateOfferAndSetAsLocal());
2111 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2112 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2113}
2114
Eldar Rello353a7182019-11-25 18:49:44 +02002115TEST_F(PeerConnectionJsepTest, RollbackMultipleStreamChanges) {
2116 auto callee = CreatePeerConnection();
2117 auto caller = CreatePeerConnection();
2118 caller->AddAudioTrack("a_1", {"id_1"});
2119 caller->AddVideoTrack("v_0", {"id_0"}); // Provide an extra stream id.
2120 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2121 EXPECT_TRUE(
2122 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
2123 caller->pc()->GetTransceivers()[0]->sender()->SetStreams({"id_2"});
2124 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2125 caller->pc()->GetTransceivers()[0]->sender()->SetStreams({"id_3"});
2126 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
2127 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->receiver()->stream_ids()[0],
2128 "id_3");
2129 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
2130 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->receiver()->stream_ids().size(),
2131 1u);
2132 EXPECT_EQ(callee->pc()->GetTransceivers()[0]->receiver()->stream_ids()[0],
2133 "id_1");
2134}
2135
Eldar Rellod85ea752020-02-19 20:41:07 +02002136TEST_F(PeerConnectionJsepTest, DataChannelImplicitRollback) {
2137 RTCConfiguration config;
2138 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
2139 config.enable_implicit_rollback = true;
2140 auto caller = CreatePeerConnection(config);
2141 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2142 auto callee = CreatePeerConnection(config);
2143 callee->CreateDataChannel("dummy");
2144 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2145 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2146 EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal());
Henrik Boströme574a312020-08-25 10:20:11 +02002147 EXPECT_TRUE(callee->observer()->legacy_renegotiation_needed());
2148 EXPECT_TRUE(callee->observer()->has_negotiation_needed_event());
Eldar Rellod85ea752020-02-19 20:41:07 +02002149 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2150}
2151
2152TEST_F(PeerConnectionJsepTest, RollbackRemoteDataChannelThenAddTransceiver) {
2153 auto caller = CreatePeerConnection();
2154 auto callee = CreatePeerConnection();
2155 caller->CreateDataChannel("dummy");
2156 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2157 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
2158 callee->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2159 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2160}
2161
2162TEST_F(PeerConnectionJsepTest,
2163 RollbackRemoteDataChannelThenAddTransceiverAndDataChannel) {
2164 auto caller = CreatePeerConnection();
2165 auto callee = CreatePeerConnection();
2166 caller->CreateDataChannel("dummy");
2167 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2168 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
2169 callee->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2170 callee->CreateDataChannel("dummy");
2171 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2172}
2173
2174TEST_F(PeerConnectionJsepTest, RollbackRemoteDataChannelThenAddDataChannel) {
2175 auto caller = CreatePeerConnection();
2176 auto callee = CreatePeerConnection();
2177 caller->CreateDataChannel("dummy");
2178 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2179 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
2180 callee->CreateDataChannel("dummy");
2181 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2182}
2183
2184TEST_F(PeerConnectionJsepTest, RollbackRemoteTransceiverThenAddDataChannel) {
2185 auto caller = CreatePeerConnection();
2186 auto callee = CreatePeerConnection();
2187 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2188 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2189 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
2190 callee->CreateDataChannel("dummy");
2191 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2192}
2193
2194TEST_F(PeerConnectionJsepTest,
2195 RollbackRemoteTransceiverThenAddDataChannelAndTransceiver) {
2196 auto caller = CreatePeerConnection();
2197 auto callee = CreatePeerConnection();
2198 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2199 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
2200 EXPECT_TRUE(callee->SetRemoteDescription(callee->CreateRollback()));
2201 callee->CreateDataChannel("dummy");
2202 callee->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
2203 EXPECT_TRUE(callee->CreateOfferAndSetAsLocal());
2204}
2205
Eldar Rellod9ebe012020-03-18 20:41:45 +02002206TEST_F(PeerConnectionJsepTest, RollbackRtpDataChannel) {
2207 RTCConfiguration config;
2208 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
2209 config.enable_rtp_data_channel = true;
2210 auto pc = CreatePeerConnection(config);
2211 pc->CreateDataChannel("dummy");
2212 auto offer = pc->CreateOffer();
2213 EXPECT_TRUE(pc->CreateOfferAndSetAsLocal());
2214 EXPECT_TRUE(pc->SetRemoteDescription(pc->CreateRollback()));
2215 EXPECT_TRUE(pc->SetLocalDescription(std::move(offer)));
2216}
2217
Steve Antondcc3c022017-12-22 16:02:54 -08002218} // namespace webrtc