blob: 161f5342ea042130f880d67f4dd116bc81f21b12 [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
Danil Chapovalov9da25bd2019-06-20 10:19:42 +020011#include "api/task_queue/default_task_queue_factory.h"
Steve Anton10542f22019-01-11 09:11:00 -080012#include "media/engine/webrtc_media_engine.h"
Danil Chapovalov9da25bd2019-06-20 10:19:42 +020013#include "media/engine/webrtc_media_engine_defaults.h"
Steve Anton10542f22019-01-11 09:11:00 -080014#include "pc/media_session.h"
15#include "pc/peer_connection_factory.h"
16#include "pc/peer_connection_wrapper.h"
17#include "pc/sdp_utils.h"
Steve Antondcc3c022017-12-22 16:02:54 -080018#ifdef WEBRTC_ANDROID
Steve Anton10542f22019-01-11 09:11:00 -080019#include "pc/test/android_test_initializer.h"
Steve Antondcc3c022017-12-22 16:02:54 -080020#endif
Karl Wiberg918f50c2018-07-05 11:40:33 +020021#include "absl/memory/memory.h"
Steve Anton10542f22019-01-11 09:11:00 -080022#include "pc/test/fake_audio_capture_module.h"
23#include "pc/test/fake_sctp_transport.h"
Steve Antondcc3c022017-12-22 16:02:54 -080024#include "rtc_base/gunit.h"
Steve Anton10542f22019-01-11 09:11:00 -080025#include "rtc_base/virtual_socket_server.h"
Steve Antondcc3c022017-12-22 16:02:54 -080026#include "test/gmock.h"
27
28// This file contains tests that ensure the PeerConnection's implementation of
29// CreateOffer/CreateAnswer/SetLocalDescription/SetRemoteDescription conform
30// to the JavaScript Session Establishment Protocol (JSEP).
31// For now these semantics are only available when configuring the
32// PeerConnection with Unified Plan, but eventually that will be the default.
33
34namespace webrtc {
35
36using cricket::MediaContentDescription;
37using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
38using ::testing::Values;
39using ::testing::Combine;
40using ::testing::ElementsAre;
Steve Antonef65ef12018-01-10 17:15:20 -080041using ::testing::UnorderedElementsAre;
Steve Antondcc3c022017-12-22 16:02:54 -080042
Steve Antonfa2260d2017-12-28 16:38:23 -080043class PeerConnectionFactoryForJsepTest : public PeerConnectionFactory {
44 public:
45 PeerConnectionFactoryForJsepTest()
Danil Chapovalovf5258be2019-03-19 17:45:24 +010046 : PeerConnectionFactory([] {
47 PeerConnectionFactoryDependencies dependencies;
48 dependencies.worker_thread = rtc::Thread::Current();
49 dependencies.network_thread = rtc::Thread::Current();
50 dependencies.signaling_thread = rtc::Thread::Current();
Danil Chapovalov9da25bd2019-06-20 10:19:42 +020051 dependencies.task_queue_factory = CreateDefaultTaskQueueFactory();
52 cricket::MediaEngineDependencies media_deps;
53 media_deps.task_queue_factory = dependencies.task_queue_factory.get();
54 media_deps.adm = FakeAudioCaptureModule::Create();
55 SetMediaEngineDefaults(&media_deps);
56 dependencies.media_engine =
57 cricket::CreateMediaEngine(std::move(media_deps));
Danil Chapovalovf5258be2019-03-19 17:45:24 +010058 dependencies.call_factory = CreateCallFactory();
59 return dependencies;
60 }()) {}
Steve Antonfa2260d2017-12-28 16:38:23 -080061
62 std::unique_ptr<cricket::SctpTransportInternalFactory>
63 CreateSctpTransportInternalFactory() {
Karl Wiberg918f50c2018-07-05 11:40:33 +020064 return absl::make_unique<FakeSctpTransportFactory>();
Steve Antonfa2260d2017-12-28 16:38:23 -080065 }
66};
67
Steve Antondcc3c022017-12-22 16:02:54 -080068class PeerConnectionJsepTest : public ::testing::Test {
69 protected:
70 typedef std::unique_ptr<PeerConnectionWrapper> WrapperPtr;
71
72 PeerConnectionJsepTest()
73 : vss_(new rtc::VirtualSocketServer()), main_(vss_.get()) {
74#ifdef WEBRTC_ANDROID
75 InitializeAndroidObjects();
76#endif
Steve Antondcc3c022017-12-22 16:02:54 -080077 }
78
79 WrapperPtr CreatePeerConnection() {
80 RTCConfiguration config;
81 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
82 return CreatePeerConnection(config);
83 }
84
85 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
Steve Antonfa2260d2017-12-28 16:38:23 -080086 rtc::scoped_refptr<PeerConnectionFactory> pc_factory(
87 new rtc::RefCountedObject<PeerConnectionFactoryForJsepTest>());
88 RTC_CHECK(pc_factory->Initialize());
Karl Wiberg918f50c2018-07-05 11:40:33 +020089 auto observer = absl::make_unique<MockPeerConnectionObserver>();
Steve Antonfa2260d2017-12-28 16:38:23 -080090 auto pc = pc_factory->CreatePeerConnection(config, nullptr, nullptr,
91 observer.get());
Steve Antondcc3c022017-12-22 16:02:54 -080092 if (!pc) {
93 return nullptr;
94 }
95
Yves Gerey4e933292018-10-31 15:36:05 +010096 observer->SetPeerConnectionInterface(pc.get());
Karl Wiberg918f50c2018-07-05 11:40:33 +020097 return absl::make_unique<PeerConnectionWrapper>(pc_factory, pc,
98 std::move(observer));
Steve Antondcc3c022017-12-22 16:02:54 -080099 }
100
101 std::unique_ptr<rtc::VirtualSocketServer> vss_;
102 rtc::AutoSocketServerThread main_;
Steve Antondcc3c022017-12-22 16:02:54 -0800103};
104
105// Tests for JSEP initial offer generation.
106
107// Test that an offer created by a PeerConnection with no transceivers generates
108// no media sections.
109TEST_F(PeerConnectionJsepTest, EmptyInitialOffer) {
110 auto caller = CreatePeerConnection();
Steve Antonfa2260d2017-12-28 16:38:23 -0800111
Steve Antondcc3c022017-12-22 16:02:54 -0800112 auto offer = caller->CreateOffer();
Steve Antonfa2260d2017-12-28 16:38:23 -0800113 ASSERT_EQ(0u, offer->description()->contents().size());
Steve Antondcc3c022017-12-22 16:02:54 -0800114}
115
116// Test that an initial offer with one audio track generates one audio media
117// section.
118TEST_F(PeerConnectionJsepTest, AudioOnlyInitialOffer) {
119 auto caller = CreatePeerConnection();
120 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
Steve Antondcc3c022017-12-22 16:02:54 -0800121
Steve Antonfa2260d2017-12-28 16:38:23 -0800122 auto offer = caller->CreateOffer();
Steve Antondcc3c022017-12-22 16:02:54 -0800123 auto contents = offer->description()->contents();
124 ASSERT_EQ(1u, contents.size());
125 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, contents[0].media_description()->type());
126}
127
128// Test than an initial offer with one video track generates one video media
129// section
130TEST_F(PeerConnectionJsepTest, VideoOnlyInitialOffer) {
131 auto caller = CreatePeerConnection();
132 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
Steve Antondcc3c022017-12-22 16:02:54 -0800133
Steve Antonfa2260d2017-12-28 16:38:23 -0800134 auto offer = caller->CreateOffer();
Steve Antondcc3c022017-12-22 16:02:54 -0800135 auto contents = offer->description()->contents();
136 ASSERT_EQ(1u, contents.size());
137 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, contents[0].media_description()->type());
138}
139
Steve Antonfa2260d2017-12-28 16:38:23 -0800140// Test that an initial offer with one data channel generates one data media
141// section.
142TEST_F(PeerConnectionJsepTest, DataOnlyInitialOffer) {
143 auto caller = CreatePeerConnection();
144 caller->CreateDataChannel("dc");
145
146 auto offer = caller->CreateOffer();
147 auto contents = offer->description()->contents();
148 ASSERT_EQ(1u, contents.size());
149 EXPECT_EQ(cricket::MEDIA_TYPE_DATA, contents[0].media_description()->type());
150}
151
152// Test that creating multiple data channels only results in one data section
153// generated in the offer.
154TEST_F(PeerConnectionJsepTest, MultipleDataChannelsCreateOnlyOneDataSection) {
155 auto caller = CreatePeerConnection();
156 caller->CreateDataChannel("first");
157 caller->CreateDataChannel("second");
158 caller->CreateDataChannel("third");
159
160 auto offer = caller->CreateOffer();
161 ASSERT_EQ(1u, offer->description()->contents().size());
162}
163
Steve Antondcc3c022017-12-22 16:02:54 -0800164// Test that multiple media sections in the initial offer are ordered in the
165// order the transceivers were added to the PeerConnection. This is required by
166// JSEP section 5.2.1.
167TEST_F(PeerConnectionJsepTest, MediaSectionsInInitialOfferOrderedCorrectly) {
168 auto caller = CreatePeerConnection();
169 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
170 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
171 RtpTransceiverInit init;
172 init.direction = RtpTransceiverDirection::kSendOnly;
173 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init);
Steve Antondcc3c022017-12-22 16:02:54 -0800174
Steve Antonfa2260d2017-12-28 16:38:23 -0800175 auto offer = caller->CreateOffer();
Steve Antondcc3c022017-12-22 16:02:54 -0800176 auto contents = offer->description()->contents();
177 ASSERT_EQ(3u, contents.size());
178
179 const MediaContentDescription* media_description1 =
180 contents[0].media_description();
181 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, media_description1->type());
182 EXPECT_EQ(RtpTransceiverDirection::kSendRecv,
183 media_description1->direction());
184
185 const MediaContentDescription* media_description2 =
186 contents[1].media_description();
187 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, media_description2->type());
188 EXPECT_EQ(RtpTransceiverDirection::kSendRecv,
189 media_description2->direction());
190
191 const MediaContentDescription* media_description3 =
192 contents[2].media_description();
193 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, media_description3->type());
194 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
195 media_description3->direction());
196}
197
198// Test that media sections in the initial offer have different mids.
199TEST_F(PeerConnectionJsepTest, MediaSectionsInInitialOfferHaveDifferentMids) {
200 auto caller = CreatePeerConnection();
201 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
202 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
Steve Antonfa2260d2017-12-28 16:38:23 -0800203
Steve Antondcc3c022017-12-22 16:02:54 -0800204 auto offer = caller->CreateOffer();
Steve Antondcc3c022017-12-22 16:02:54 -0800205 auto contents = offer->description()->contents();
206 ASSERT_EQ(2u, contents.size());
207 EXPECT_NE(contents[0].name, contents[1].name);
208}
209
210TEST_F(PeerConnectionJsepTest,
211 StoppedTransceiverHasNoMediaSectionInInitialOffer) {
212 auto caller = CreatePeerConnection();
213 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
214 transceiver->Stop();
215
216 auto offer = caller->CreateOffer();
217 EXPECT_EQ(0u, offer->description()->contents().size());
218}
219
220// Tests for JSEP SetLocalDescription with a local offer.
221
222TEST_F(PeerConnectionJsepTest, SetLocalEmptyOfferCreatesNoTransceivers) {
223 auto caller = CreatePeerConnection();
Steve Antonfa2260d2017-12-28 16:38:23 -0800224
Steve Antondcc3c022017-12-22 16:02:54 -0800225 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
226
227 EXPECT_THAT(caller->pc()->GetTransceivers(), ElementsAre());
228 EXPECT_THAT(caller->pc()->GetSenders(), ElementsAre());
229 EXPECT_THAT(caller->pc()->GetReceivers(), ElementsAre());
230}
231
232TEST_F(PeerConnectionJsepTest, SetLocalOfferSetsTransceiverMid) {
233 auto caller = CreatePeerConnection();
234 auto audio_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
235 auto video_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
236
237 auto offer = caller->CreateOffer();
238 std::string audio_mid = offer->description()->contents()[0].name;
239 std::string video_mid = offer->description()->contents()[1].name;
240
241 ASSERT_TRUE(caller->SetLocalDescription(std::move(offer)));
242
243 EXPECT_EQ(audio_mid, audio_transceiver->mid());
244 EXPECT_EQ(video_mid, video_transceiver->mid());
245}
246
247// Tests for JSEP SetRemoteDescription with a remote offer.
248
249// Test that setting a remote offer with sendrecv audio and video creates two
250// transceivers, one for receiving audio and one for receiving video.
251TEST_F(PeerConnectionJsepTest, SetRemoteOfferCreatesTransceivers) {
252 auto caller = CreatePeerConnection();
253 auto caller_audio = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
254 auto caller_video = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
255 auto callee = CreatePeerConnection();
256
257 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
258
259 auto transceivers = callee->pc()->GetTransceivers();
260 ASSERT_EQ(2u, transceivers.size());
Steve Anton1bc97162018-06-25 14:04:01 -0700261
Steve Anton69470252018-02-09 11:43:08 -0800262 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, transceivers[0]->media_type());
Steve Antondcc3c022017-12-22 16:02:54 -0800263 EXPECT_EQ(caller_audio->mid(), transceivers[0]->mid());
264 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly, transceivers[0]->direction());
Steve Anton1bc97162018-06-25 14:04:01 -0700265 EXPECT_EQ(0u, transceivers[0]->sender()->stream_ids().size());
266
Steve Anton69470252018-02-09 11:43:08 -0800267 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, transceivers[1]->media_type());
Steve Antondcc3c022017-12-22 16:02:54 -0800268 EXPECT_EQ(caller_video->mid(), transceivers[1]->mid());
269 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly, transceivers[1]->direction());
Steve Anton1bc97162018-06-25 14:04:01 -0700270 EXPECT_EQ(0u, transceivers[1]->sender()->stream_ids().size());
Steve Antondcc3c022017-12-22 16:02:54 -0800271}
272
273// Test that setting a remote offer with an audio track will reuse the
274// transceiver created for a local audio track added by AddTrack.
275// This is specified in JSEP section 5.10 (Applying a Remote Description). The
276// intent is to preserve backwards compatibility with clients who only use the
277// AddTrack API.
278TEST_F(PeerConnectionJsepTest, SetRemoteOfferReusesTransceiverFromAddTrack) {
279 auto caller = CreatePeerConnection();
280 caller->AddAudioTrack("a");
281 auto caller_audio = caller->pc()->GetTransceivers()[0];
282 auto callee = CreatePeerConnection();
283 callee->AddAudioTrack("a");
284
285 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
286
287 auto transceivers = callee->pc()->GetTransceivers();
288 ASSERT_EQ(1u, transceivers.size());
289 EXPECT_EQ(MediaStreamTrackInterface::kAudioKind,
290 transceivers[0]->receiver()->track()->kind());
291 EXPECT_EQ(caller_audio->mid(), transceivers[0]->mid());
292}
293
294// Test that setting a remote offer with an audio track marked sendonly will not
295// reuse a transceiver created by AddTrack. JSEP only allows the transceiver to
296// be reused if the offer direction is sendrecv or recvonly.
297TEST_F(PeerConnectionJsepTest,
298 SetRemoteOfferDoesNotReuseTransceiverIfDirectionSendOnly) {
299 auto caller = CreatePeerConnection();
300 caller->AddAudioTrack("a");
301 auto caller_audio = caller->pc()->GetTransceivers()[0];
302 caller_audio->SetDirection(RtpTransceiverDirection::kSendOnly);
303 auto callee = CreatePeerConnection();
304 callee->AddAudioTrack("a");
305
306 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
307
308 auto transceivers = callee->pc()->GetTransceivers();
309 ASSERT_EQ(2u, transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200310 EXPECT_EQ(absl::nullopt, transceivers[0]->mid());
Steve Antondcc3c022017-12-22 16:02:54 -0800311 EXPECT_EQ(caller_audio->mid(), transceivers[1]->mid());
312}
313
314// Test that setting a remote offer with an audio track will not reuse a
315// transceiver added by AddTransceiver. The logic for reusing a transceiver is
316// specific to those added by AddTrack and is tested above.
317TEST_F(PeerConnectionJsepTest,
318 SetRemoteOfferDoesNotReuseTransceiverFromAddTransceiver) {
319 auto caller = CreatePeerConnection();
320 caller->AddAudioTrack("a");
321 auto callee = CreatePeerConnection();
322 auto transceiver = callee->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
323
324 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
325
326 auto transceivers = callee->pc()->GetTransceivers();
327 ASSERT_EQ(2u, transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200328 EXPECT_EQ(absl::nullopt, transceivers[0]->mid());
Steve Antondcc3c022017-12-22 16:02:54 -0800329 EXPECT_EQ(caller->pc()->GetTransceivers()[0]->mid(), transceivers[1]->mid());
330 EXPECT_EQ(MediaStreamTrackInterface::kAudioKind,
331 transceivers[1]->receiver()->track()->kind());
332}
333
334// Test that setting a remote offer with an audio track will not reuse a
335// transceiver created for a local video track added by AddTrack.
336TEST_F(PeerConnectionJsepTest,
337 SetRemoteOfferDoesNotReuseTransceiverOfWrongType) {
338 auto caller = CreatePeerConnection();
339 caller->AddAudioTrack("a");
340 auto callee = CreatePeerConnection();
341 auto video_sender = callee->AddVideoTrack("v");
342
343 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
344
345 auto transceivers = callee->pc()->GetTransceivers();
346 ASSERT_EQ(2u, transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200347 EXPECT_EQ(absl::nullopt, transceivers[0]->mid());
Steve Antondcc3c022017-12-22 16:02:54 -0800348 EXPECT_EQ(caller->pc()->GetTransceivers()[0]->mid(), transceivers[1]->mid());
349 EXPECT_EQ(MediaStreamTrackInterface::kAudioKind,
350 transceivers[1]->receiver()->track()->kind());
351}
352
353// Test that setting a remote offer with an audio track will not reuse a
354// stopped transceiver.
355TEST_F(PeerConnectionJsepTest, SetRemoteOfferDoesNotReuseStoppedTransceiver) {
356 auto caller = CreatePeerConnection();
357 caller->AddAudioTrack("a");
358 auto callee = CreatePeerConnection();
359 callee->AddAudioTrack("a");
360 callee->pc()->GetTransceivers()[0]->Stop();
361
362 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
363
364 auto transceivers = callee->pc()->GetTransceivers();
365 ASSERT_EQ(2u, transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200366 EXPECT_EQ(absl::nullopt, transceivers[0]->mid());
Steve Antondcc3c022017-12-22 16:02:54 -0800367 EXPECT_TRUE(transceivers[0]->stopped());
368 EXPECT_EQ(caller->pc()->GetTransceivers()[0]->mid(), transceivers[1]->mid());
369 EXPECT_FALSE(transceivers[1]->stopped());
370}
371
372// Test that audio and video transceivers created on the remote side with
373// AddTrack will all be reused if there is the same number of audio/video tracks
374// in the remote offer. Additionally, this tests that transceivers are
375// successfully matched even if they are in a different order on the remote
376// side.
377TEST_F(PeerConnectionJsepTest, SetRemoteOfferReusesTransceiversOfBothTypes) {
378 auto caller = CreatePeerConnection();
379 caller->AddVideoTrack("v");
380 caller->AddAudioTrack("a");
381 auto callee = CreatePeerConnection();
382 callee->AddAudioTrack("a");
383 callee->AddVideoTrack("v");
384
385 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
386
387 auto caller_transceivers = caller->pc()->GetTransceivers();
388 auto callee_transceivers = callee->pc()->GetTransceivers();
389 ASSERT_EQ(2u, callee_transceivers.size());
390 EXPECT_EQ(caller_transceivers[0]->mid(), callee_transceivers[1]->mid());
391 EXPECT_EQ(caller_transceivers[1]->mid(), callee_transceivers[0]->mid());
392}
393
394// Tests for JSEP initial CreateAnswer.
395
396// Test that the answer to a remote offer creates media sections for each
397// offered media in the same order and with the same mids.
398TEST_F(PeerConnectionJsepTest, CreateAnswerHasSameMidsAsOffer) {
399 auto caller = CreatePeerConnection();
400 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
401 auto second_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
402 auto third_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
Steve Antonfa2260d2017-12-28 16:38:23 -0800403 caller->CreateDataChannel("dc");
Steve Antondcc3c022017-12-22 16:02:54 -0800404 auto callee = CreatePeerConnection();
405
Steve Antonfa2260d2017-12-28 16:38:23 -0800406 auto offer = caller->CreateOffer();
407 const auto* offer_data = cricket::GetFirstDataContent(offer->description());
408 ASSERT_TRUE(
409 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
410 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
Steve Antondcc3c022017-12-22 16:02:54 -0800411
412 auto answer = callee->CreateAnswer();
413 auto contents = answer->description()->contents();
Steve Antonfa2260d2017-12-28 16:38:23 -0800414 ASSERT_EQ(4u, contents.size());
Steve Antondcc3c022017-12-22 16:02:54 -0800415 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, contents[0].media_description()->type());
Steve Antonfa2260d2017-12-28 16:38:23 -0800416 EXPECT_EQ(first_transceiver->mid(), contents[0].name);
Steve Antondcc3c022017-12-22 16:02:54 -0800417 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, contents[1].media_description()->type());
Steve Antonfa2260d2017-12-28 16:38:23 -0800418 EXPECT_EQ(second_transceiver->mid(), contents[1].name);
Steve Antondcc3c022017-12-22 16:02:54 -0800419 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, contents[2].media_description()->type());
Steve Antonfa2260d2017-12-28 16:38:23 -0800420 EXPECT_EQ(third_transceiver->mid(), contents[2].name);
421 EXPECT_EQ(cricket::MEDIA_TYPE_DATA, contents[3].media_description()->type());
422 EXPECT_EQ(offer_data->name, contents[3].name);
Steve Antondcc3c022017-12-22 16:02:54 -0800423}
424
425// Test that an answering media section is marked as rejected if the underlying
426// transceiver has been stopped.
427TEST_F(PeerConnectionJsepTest, CreateAnswerRejectsStoppedTransceiver) {
428 auto caller = CreatePeerConnection();
429 caller->AddAudioTrack("a");
430 auto callee = CreatePeerConnection();
431
432 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
433
434 callee->pc()->GetTransceivers()[0]->Stop();
435
436 auto answer = callee->CreateAnswer();
437 auto contents = answer->description()->contents();
438 ASSERT_EQ(1u, contents.size());
439 EXPECT_TRUE(contents[0].rejected);
440}
441
442// Test that CreateAnswer will generate media sections which will only send or
443// receive if the offer indicates it can do the reciprocating direction.
444// The full matrix is tested more extensively in MediaSession.
445TEST_F(PeerConnectionJsepTest, CreateAnswerNegotiatesDirection) {
446 auto caller = CreatePeerConnection();
447 RtpTransceiverInit init;
448 init.direction = RtpTransceiverDirection::kSendOnly;
449 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init);
450 auto callee = CreatePeerConnection();
451 callee->AddAudioTrack("a");
452
453 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
454
455 auto answer = callee->CreateAnswer();
456 auto contents = answer->description()->contents();
457 ASSERT_EQ(1u, contents.size());
458 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
459 contents[0].media_description()->direction());
460}
461
462// Tests for JSEP SetLocalDescription with a local answer.
463// Note that these test only the additional behaviors not covered by
464// SetLocalDescription with a local offer.
465
466// Test that SetLocalDescription with an answer sets the current_direction
467// property of the transceivers mentioned in the session description.
468TEST_F(PeerConnectionJsepTest, SetLocalAnswerUpdatesCurrentDirection) {
469 auto caller = CreatePeerConnection();
470 auto caller_audio = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
471 caller_audio->SetDirection(RtpTransceiverDirection::kRecvOnly);
472 auto callee = CreatePeerConnection();
473 callee->AddAudioTrack("a");
474
475 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
476 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
477
478 auto transceivers = callee->pc()->GetTransceivers();
479 ASSERT_EQ(1u, transceivers.size());
480 // Since the offer was recvonly and the transceiver direction is sendrecv,
481 // the negotiated direction will be sendonly.
482 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
483 transceivers[0]->current_direction());
484}
485
486// Tests for JSEP SetRemoteDescription with a remote answer.
487// Note that these test only the additional behaviors not covered by
488// SetRemoteDescription with a remote offer.
489
490TEST_F(PeerConnectionJsepTest, SetRemoteAnswerUpdatesCurrentDirection) {
491 auto caller = CreatePeerConnection();
492 caller->AddAudioTrack("a");
493 auto callee = CreatePeerConnection();
494 callee->AddAudioTrack("a");
495 auto callee_audio = callee->pc()->GetTransceivers()[0];
496 callee_audio->SetDirection(RtpTransceiverDirection::kSendOnly);
497
498 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
499 ASSERT_TRUE(
500 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
501
502 auto transceivers = caller->pc()->GetTransceivers();
503 ASSERT_EQ(1u, transceivers.size());
504 // Since the remote transceiver was set to sendonly, the negotiated direction
505 // in the answer would be sendonly which we apply as recvonly to the local
506 // transceiver.
507 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
508 transceivers[0]->current_direction());
509}
510
511// Tests for multiple round trips.
512
513// Test that setting a transceiver with the inactive direction does not stop it
514// on either the caller or the callee.
515TEST_F(PeerConnectionJsepTest, SettingTransceiverInactiveDoesNotStopIt) {
516 auto caller = CreatePeerConnection();
517 caller->AddAudioTrack("a");
518 auto callee = CreatePeerConnection();
519 callee->AddAudioTrack("a");
520 callee->pc()->GetTransceivers()[0]->SetDirection(
521 RtpTransceiverDirection::kInactive);
522
523 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
524 ASSERT_TRUE(
525 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
526
527 EXPECT_FALSE(caller->pc()->GetTransceivers()[0]->stopped());
528 EXPECT_FALSE(callee->pc()->GetTransceivers()[0]->stopped());
529}
530
531// Test that if a transceiver had been associated and later stopped, then a
532// media section is still generated for it and the media section is marked as
533// rejected.
534TEST_F(PeerConnectionJsepTest,
535 ReOfferMediaSectionForAssociatedStoppedTransceiverIsRejected) {
536 auto caller = CreatePeerConnection();
537 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
538 auto callee = CreatePeerConnection();
539
540 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
541 ASSERT_TRUE(
542 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
543
544 ASSERT_TRUE(transceiver->mid());
545 transceiver->Stop();
546
547 auto reoffer = caller->CreateOffer();
548 auto contents = reoffer->description()->contents();
549 ASSERT_EQ(1u, contents.size());
550 EXPECT_TRUE(contents[0].rejected);
551}
552
553// Test that stopping an associated transceiver on the caller side will stop the
554// corresponding transceiver on the remote side when the remote offer is
555// applied.
556TEST_F(PeerConnectionJsepTest,
557 StoppingTransceiverInOfferStopsTransceiverOnRemoteSide) {
558 auto caller = CreatePeerConnection();
559 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
560 auto callee = CreatePeerConnection();
561
562 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
563 ASSERT_TRUE(
564 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
565
566 transceiver->Stop();
567
568 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
569
570 auto transceivers = callee->pc()->GetTransceivers();
571 EXPECT_TRUE(transceivers[0]->stopped());
572 EXPECT_TRUE(transceivers[0]->mid());
573}
574
575// Test that CreateOffer will only generate a recycled media section if the
576// transceiver to be recycled has been seen stopped by the other side first.
577TEST_F(PeerConnectionJsepTest,
578 CreateOfferDoesNotRecycleMediaSectionIfFirstStopped) {
579 auto caller = CreatePeerConnection();
580 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
581 auto callee = CreatePeerConnection();
582
583 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
584 ASSERT_TRUE(
585 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
586
587 auto second_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
588 first_transceiver->Stop();
589
590 auto reoffer = caller->CreateOffer();
591 auto contents = reoffer->description()->contents();
592 ASSERT_EQ(2u, contents.size());
593 EXPECT_TRUE(contents[0].rejected);
594 EXPECT_FALSE(contents[1].rejected);
595}
596
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800597// Test that the offer/answer and the transceivers are correctly generated and
598// updated when the media section is recycled after the callee stops a
599// transceiver and sends an answer with a 0 port.
600TEST_F(PeerConnectionJsepTest,
601 RecycleMediaSectionWhenStoppingTransceiverOnAnswerer) {
602 auto caller = CreatePeerConnection();
603 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
604 auto callee = CreatePeerConnection();
605
606 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
607 callee->pc()->GetTransceivers()[0]->Stop();
608 ASSERT_TRUE(
609 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
610 EXPECT_TRUE(first_transceiver->stopped());
611 // First transceivers aren't dissociated yet.
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();
614 EXPECT_EQ(first_mid, callee->pc()->GetTransceivers()[0]->mid());
615
616 // New offer exchange with new transceivers that recycles the m section
617 // correctly.
618 caller->AddAudioTrack("audio2");
619 callee->AddAudioTrack("audio2");
620 auto offer = caller->CreateOffer();
621 auto offer_contents = offer->description()->contents();
622 std::string second_mid = offer_contents[0].name;
623 ASSERT_EQ(1u, offer_contents.size());
624 EXPECT_FALSE(offer_contents[0].rejected);
625 EXPECT_NE(first_mid, second_mid);
626
627 // Setting the offer on each side will dissociate the first transceivers and
628 // associate the new transceivers.
629 ASSERT_TRUE(
630 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200631 EXPECT_EQ(absl::nullopt, first_transceiver->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800632 EXPECT_EQ(second_mid, caller->pc()->GetTransceivers()[1]->mid());
633 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200634 EXPECT_EQ(absl::nullopt, callee->pc()->GetTransceivers()[0]->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800635 EXPECT_EQ(second_mid, callee->pc()->GetTransceivers()[1]->mid());
636
637 // The new answer should also recycle the m section correctly.
638 auto answer = callee->CreateAnswer();
639 auto answer_contents = answer->description()->contents();
640 ASSERT_EQ(1u, answer_contents.size());
641 EXPECT_FALSE(answer_contents[0].rejected);
642 EXPECT_EQ(second_mid, answer_contents[0].name);
643
644 // Finishing the negotiation shouldn't add or dissociate any transceivers.
645 ASSERT_TRUE(
646 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
647 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
648 auto caller_transceivers = caller->pc()->GetTransceivers();
649 ASSERT_EQ(2u, caller_transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200650 EXPECT_EQ(absl::nullopt, caller_transceivers[0]->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800651 EXPECT_EQ(second_mid, caller_transceivers[1]->mid());
652 auto callee_transceivers = callee->pc()->GetTransceivers();
653 ASSERT_EQ(2u, callee_transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200654 EXPECT_EQ(absl::nullopt, callee_transceivers[0]->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800655 EXPECT_EQ(second_mid, callee_transceivers[1]->mid());
656}
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()));
666 first_transceiver->Stop();
667 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)));
677 EXPECT_FALSE(caller->pc()->GetTransceivers()[1]->stopped());
678 std::string second_mid = offer_contents[0].name;
679
680 // Create another new offer and set the local description again without the
681 // rest of any negotation ocurring.
682 auto second_offer = caller->CreateOffer();
683 auto second_offer_contents = second_offer->description()->contents();
684 ASSERT_EQ(1u, second_offer_contents.size());
685 EXPECT_FALSE(second_offer_contents[0].rejected);
686 // The mid shouldn't change.
687 EXPECT_EQ(second_mid, second_offer_contents[0].name);
688
689 ASSERT_TRUE(caller->SetLocalDescription(std::move(second_offer)));
690 // Make sure that the caller's transceivers are associated correctly.
691 auto caller_transceivers = caller->pc()->GetTransceivers();
692 ASSERT_EQ(2u, caller_transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200693 EXPECT_EQ(absl::nullopt, caller_transceivers[0]->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800694 EXPECT_EQ(second_mid, caller_transceivers[1]->mid());
695 EXPECT_FALSE(caller_transceivers[1]->stopped());
696}
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();
731 first_transceiver->Stop();
732
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();
758 ASSERT_EQ(2u, callee_transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200759 EXPECT_EQ(absl::nullopt, callee_transceivers[0]->mid());
Steve Anton69470252018-02-09 11:43:08 -0800760 EXPECT_EQ(first_type_, callee_transceivers[0]->media_type());
Steve Antondcc3c022017-12-22 16:02:54 -0800761 EXPECT_EQ(second_mid, callee_transceivers[1]->mid());
Steve Anton69470252018-02-09 11:43:08 -0800762 EXPECT_EQ(second_type_, callee_transceivers[1]->media_type());
Steve Antondcc3c022017-12-22 16:02:54 -0800763
764 // The answer should have only one media section for the new transceiver.
765 auto answer = callee->CreateAnswer();
766 auto answer_contents = answer->description()->contents();
767 ASSERT_EQ(1u, answer_contents.size());
768 EXPECT_FALSE(answer_contents[0].rejected);
769 EXPECT_EQ(second_mid, answer_contents[0].name);
770 EXPECT_EQ(second_type_, answer_contents[0].media_description()->type());
771
772 // Setting the local answer should succeed.
773 ASSERT_TRUE(
774 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
775
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800776 // Setting the remote answer should succeed and not create any new
777 // transceivers.
Steve Antondcc3c022017-12-22 16:02:54 -0800778 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800779 ASSERT_EQ(2u, caller->pc()->GetTransceivers().size());
780 ASSERT_EQ(2u, callee->pc()->GetTransceivers().size());
Steve Antondcc3c022017-12-22 16:02:54 -0800781}
782
Steve Anton5c72e712018-12-10 14:25:30 -0800783// Test that recycling works properly when a new transceiver recycles an m=
784// section that was rejected in only the current remote description.
785TEST_P(RecycleMediaSectionTest, CurrentRemoteOnlyRejected) {
786 auto caller = CreatePeerConnection();
787 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
788 auto callee = CreatePeerConnection();
789
790 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
791
792 std::string first_mid = *caller_first_transceiver->mid();
793 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
794 auto callee_first_transceiver = callee->pc()->GetTransceivers()[0];
795 callee_first_transceiver->Stop();
796
797 // The answer will have a rejected m= section.
798 ASSERT_TRUE(
799 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
800
801 // The offer should reuse the previous media section but allocate a new MID
802 // and change the media type.
803 auto caller_second_transceiver = caller->AddTransceiver(second_type_);
804 auto offer = caller->CreateOffer();
805 const auto& offer_contents = offer->description()->contents();
806 ASSERT_EQ(1u, offer_contents.size());
807 EXPECT_FALSE(offer_contents[0].rejected);
808 EXPECT_EQ(second_type_, offer_contents[0].media_description()->type());
809 std::string second_mid = offer_contents[0].name;
810 EXPECT_NE(first_mid, second_mid);
811
812 // Setting the local offer will dissociate the previous transceiver and set
813 // the MID for the new transceiver.
814 ASSERT_TRUE(
815 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
816 EXPECT_EQ(absl::nullopt, caller_first_transceiver->mid());
817 EXPECT_EQ(second_mid, caller_second_transceiver->mid());
818
819 // Setting the remote offer will dissociate the previous transceiver and
820 // create a new transceiver for the media section.
821 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
822 auto callee_transceivers = callee->pc()->GetTransceivers();
823 ASSERT_EQ(2u, callee_transceivers.size());
824 EXPECT_EQ(absl::nullopt, callee_transceivers[0]->mid());
825 EXPECT_EQ(first_type_, callee_transceivers[0]->media_type());
826 EXPECT_EQ(second_mid, callee_transceivers[1]->mid());
827 EXPECT_EQ(second_type_, callee_transceivers[1]->media_type());
828
829 // The answer should have only one media section for the new transceiver.
830 auto answer = callee->CreateAnswer();
831 auto answer_contents = answer->description()->contents();
832 ASSERT_EQ(1u, answer_contents.size());
833 EXPECT_FALSE(answer_contents[0].rejected);
834 EXPECT_EQ(second_mid, answer_contents[0].name);
835 EXPECT_EQ(second_type_, answer_contents[0].media_description()->type());
836
837 // Setting the local answer should succeed.
838 ASSERT_TRUE(
839 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
840
841 // Setting the remote answer should succeed and not create any new
842 // transceivers.
843 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
844 ASSERT_EQ(2u, caller->pc()->GetTransceivers().size());
845 ASSERT_EQ(2u, callee->pc()->GetTransceivers().size());
846}
847
848// Test that recycling works properly when a new transceiver recycles an m=
849// section that was rejected only in the current local description.
850TEST_P(RecycleMediaSectionTest, CurrentLocalOnlyRejected) {
851 auto caller = CreatePeerConnection();
852 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
853 auto callee = CreatePeerConnection();
854
855 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
856
857 std::string first_mid = *caller_first_transceiver->mid();
858 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
859 auto callee_first_transceiver = callee->pc()->GetTransceivers()[0];
860 callee_first_transceiver->Stop();
861
862 // The answer will have a rejected m= section.
863 ASSERT_TRUE(
864 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
865
866 // The offer should reuse the previous media section but allocate a new MID
867 // and change the media type.
868 auto callee_second_transceiver = callee->AddTransceiver(second_type_);
869 auto offer = callee->CreateOffer();
870 const auto& offer_contents = offer->description()->contents();
871 ASSERT_EQ(1u, offer_contents.size());
872 EXPECT_FALSE(offer_contents[0].rejected);
873 EXPECT_EQ(second_type_, offer_contents[0].media_description()->type());
874 std::string second_mid = offer_contents[0].name;
875 EXPECT_NE(first_mid, second_mid);
876
877 // Setting the local offer will dissociate the previous transceiver and set
878 // the MID for the new transceiver.
879 ASSERT_TRUE(
880 callee->SetLocalDescription(CloneSessionDescription(offer.get())));
881 EXPECT_EQ(absl::nullopt, callee_first_transceiver->mid());
882 EXPECT_EQ(second_mid, callee_second_transceiver->mid());
883
884 // Setting the remote offer will dissociate the previous transceiver and
885 // create a new transceiver for the media section.
886 ASSERT_TRUE(caller->SetRemoteDescription(std::move(offer)));
887 auto caller_transceivers = caller->pc()->GetTransceivers();
888 ASSERT_EQ(2u, caller_transceivers.size());
889 EXPECT_EQ(absl::nullopt, caller_transceivers[0]->mid());
890 EXPECT_EQ(first_type_, caller_transceivers[0]->media_type());
891 EXPECT_EQ(second_mid, caller_transceivers[1]->mid());
892 EXPECT_EQ(second_type_, caller_transceivers[1]->media_type());
893
894 // The answer should have only one media section for the new transceiver.
895 auto answer = caller->CreateAnswer();
896 auto answer_contents = answer->description()->contents();
897 ASSERT_EQ(1u, answer_contents.size());
898 EXPECT_FALSE(answer_contents[0].rejected);
899 EXPECT_EQ(second_mid, answer_contents[0].name);
900 EXPECT_EQ(second_type_, answer_contents[0].media_description()->type());
901
902 // Setting the local answer should succeed.
903 ASSERT_TRUE(
904 caller->SetLocalDescription(CloneSessionDescription(answer.get())));
905
906 // Setting the remote answer should succeed and not create any new
907 // transceivers.
908 ASSERT_TRUE(callee->SetRemoteDescription(std::move(answer)));
909 ASSERT_EQ(2u, callee->pc()->GetTransceivers().size());
910 ASSERT_EQ(2u, caller->pc()->GetTransceivers().size());
911}
912
913// Test that a m= section is *not* recycled if the media section is only
914// rejected in the pending local description and there is no current remote
915// description.
916TEST_P(RecycleMediaSectionTest, PendingLocalRejectedAndNoRemote) {
917 auto caller = CreatePeerConnection();
918 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
919
920 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
921
922 std::string first_mid = *caller_first_transceiver->mid();
923 caller_first_transceiver->Stop();
924
925 // The reoffer will have a rejected m= section.
926 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
927
928 auto caller_second_transceiver = caller->AddTransceiver(second_type_);
929
930 // The reoffer should not recycle the existing m= section since it is not
931 // rejected in either the *current* local or *current* remote description.
932 auto reoffer = caller->CreateOffer();
933 auto reoffer_contents = reoffer->description()->contents();
934 ASSERT_EQ(2u, reoffer_contents.size());
935 EXPECT_TRUE(reoffer_contents[0].rejected);
936 EXPECT_EQ(first_type_, reoffer_contents[0].media_description()->type());
937 EXPECT_EQ(first_mid, reoffer_contents[0].name);
938 EXPECT_FALSE(reoffer_contents[1].rejected);
939 EXPECT_EQ(second_type_, reoffer_contents[1].media_description()->type());
940 std::string second_mid = reoffer_contents[1].name;
941 EXPECT_NE(first_mid, second_mid);
942
943 ASSERT_TRUE(caller->SetLocalDescription(std::move(reoffer)));
944
945 // Both RtpTransceivers are associated.
946 EXPECT_EQ(first_mid, caller_first_transceiver->mid());
947 EXPECT_EQ(second_mid, caller_second_transceiver->mid());
948}
949
950// Test that a m= section is *not* recycled if the media section is only
951// rejected in the pending local description and not rejected in the current
952// remote description.
953TEST_P(RecycleMediaSectionTest, PendingLocalRejectedAndNotRejectedRemote) {
954 auto caller = CreatePeerConnection();
955 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
956 auto callee = CreatePeerConnection();
957
958 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
959
960 std::string first_mid = *caller_first_transceiver->mid();
961 caller_first_transceiver->Stop();
962
963 // The reoffer will have a rejected m= section.
964 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
965
966 auto caller_second_transceiver = caller->AddTransceiver(second_type_);
967
968 // The reoffer should not recycle the existing m= section since it is not
969 // rejected in either the *current* local or *current* remote description.
970 auto reoffer = caller->CreateOffer();
971 auto reoffer_contents = reoffer->description()->contents();
972 ASSERT_EQ(2u, reoffer_contents.size());
973 EXPECT_TRUE(reoffer_contents[0].rejected);
974 EXPECT_EQ(first_type_, reoffer_contents[0].media_description()->type());
975 EXPECT_EQ(first_mid, reoffer_contents[0].name);
976 EXPECT_FALSE(reoffer_contents[1].rejected);
977 EXPECT_EQ(second_type_, reoffer_contents[1].media_description()->type());
978 std::string second_mid = reoffer_contents[1].name;
979 EXPECT_NE(first_mid, second_mid);
980
981 ASSERT_TRUE(caller->SetLocalDescription(std::move(reoffer)));
982
983 // Both RtpTransceivers are associated.
984 EXPECT_EQ(first_mid, caller_first_transceiver->mid());
985 EXPECT_EQ(second_mid, caller_second_transceiver->mid());
986}
987
988// Test that an m= section is *not* recycled if the media section is only
989// rejected in the pending remote description and there is no current local
990// description.
991TEST_P(RecycleMediaSectionTest, PendingRemoteRejectedAndNoLocal) {
992 auto caller = CreatePeerConnection();
993 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
994 auto callee = CreatePeerConnection();
995
996 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
997
998 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
999 auto callee_first_transceiver = callee->pc()->GetTransceivers()[0];
1000 std::string first_mid = *callee_first_transceiver->mid();
1001 caller_first_transceiver->Stop();
1002
1003 // The reoffer will have a rejected m= section.
1004 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1005
1006 auto callee_second_transceiver = callee->AddTransceiver(second_type_);
1007
1008 // The reoffer should not recycle the existing m= section since it is not
1009 // rejected in either the *current* local or *current* remote description.
1010 auto reoffer = callee->CreateOffer();
1011 auto reoffer_contents = reoffer->description()->contents();
1012 ASSERT_EQ(2u, reoffer_contents.size());
1013 EXPECT_TRUE(reoffer_contents[0].rejected);
1014 EXPECT_EQ(first_type_, reoffer_contents[0].media_description()->type());
1015 EXPECT_EQ(first_mid, reoffer_contents[0].name);
1016 EXPECT_FALSE(reoffer_contents[1].rejected);
1017 EXPECT_EQ(second_type_, reoffer_contents[1].media_description()->type());
1018 std::string second_mid = reoffer_contents[1].name;
1019 EXPECT_NE(first_mid, second_mid);
1020
1021 // Note: Cannot actually set the reoffer since the callee is in the signaling
1022 // state 'have-remote-offer'.
1023}
1024
1025// Test that an m= section is *not* recycled if the media section is only
1026// rejected in the pending remote description and not rejected in the current
1027// local description.
1028TEST_P(RecycleMediaSectionTest, PendingRemoteRejectedAndNotRejectedLocal) {
1029 auto caller = CreatePeerConnection();
1030 auto caller_first_transceiver = caller->AddTransceiver(first_type_);
1031 auto callee = CreatePeerConnection();
1032
1033 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1034
1035 ASSERT_EQ(1u, callee->pc()->GetTransceivers().size());
1036 auto callee_first_transceiver = callee->pc()->GetTransceivers()[0];
1037 std::string first_mid = *callee_first_transceiver->mid();
1038 caller_first_transceiver->Stop();
1039
1040 // The reoffer will have a rejected m= section.
1041 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1042
1043 auto callee_second_transceiver = callee->AddTransceiver(second_type_);
1044
1045 // The reoffer should not recycle the existing m= section since it is not
1046 // rejected in either the *current* local or *current* remote description.
1047 auto reoffer = callee->CreateOffer();
1048 auto reoffer_contents = reoffer->description()->contents();
1049 ASSERT_EQ(2u, reoffer_contents.size());
1050 EXPECT_TRUE(reoffer_contents[0].rejected);
1051 EXPECT_EQ(first_type_, reoffer_contents[0].media_description()->type());
1052 EXPECT_EQ(first_mid, reoffer_contents[0].name);
1053 EXPECT_FALSE(reoffer_contents[1].rejected);
1054 EXPECT_EQ(second_type_, reoffer_contents[1].media_description()->type());
1055 std::string second_mid = reoffer_contents[1].name;
1056 EXPECT_NE(first_mid, second_mid);
1057
1058 // Note: Cannot actually set the reoffer since the callee is in the signaling
1059 // state 'have-remote-offer'.
1060}
1061
Steve Antondcc3c022017-12-22 16:02:54 -08001062// Test all combinations of audio and video as the first and second media type
1063// for the media section. This is needed for full test coverage because
1064// MediaSession has separate functions for processing audio and video media
1065// sections.
Mirko Bonadeic84f6612019-01-31 12:20:57 +01001066INSTANTIATE_TEST_SUITE_P(
Steve Antondcc3c022017-12-22 16:02:54 -08001067 PeerConnectionJsepTest,
1068 RecycleMediaSectionTest,
1069 Combine(Values(cricket::MEDIA_TYPE_AUDIO, cricket::MEDIA_TYPE_VIDEO),
1070 Values(cricket::MEDIA_TYPE_AUDIO, cricket::MEDIA_TYPE_VIDEO)));
1071
Steve Antonfa2260d2017-12-28 16:38:23 -08001072// Test that a new data channel section will not reuse a recycleable audio or
1073// video media section. Additionally, tests that the new section is added to the
1074// end of the session description.
1075TEST_F(PeerConnectionJsepTest, DataChannelDoesNotRecycleMediaSection) {
1076 auto caller = CreatePeerConnection();
1077 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1078 auto callee = CreatePeerConnection();
1079
1080 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1081
1082 transceiver->Stop();
1083
1084 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1085
1086 caller->CreateDataChannel("dc");
1087
1088 auto offer = caller->CreateOffer();
1089 auto offer_contents = offer->description()->contents();
1090 ASSERT_EQ(2u, offer_contents.size());
1091 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO,
1092 offer_contents[0].media_description()->type());
1093 EXPECT_EQ(cricket::MEDIA_TYPE_DATA,
1094 offer_contents[1].media_description()->type());
1095
1096 ASSERT_TRUE(
1097 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
1098 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1099
1100 auto answer = callee->CreateAnswer();
1101 auto answer_contents = answer->description()->contents();
1102 ASSERT_EQ(2u, answer_contents.size());
1103 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO,
1104 answer_contents[0].media_description()->type());
1105 EXPECT_EQ(cricket::MEDIA_TYPE_DATA,
1106 answer_contents[1].media_description()->type());
1107}
1108
1109// Test that if a new track is added to an existing session that has a data,
1110// the new section comes at the end of the new offer, after the existing data
1111// section.
1112TEST_F(PeerConnectionJsepTest, AudioTrackAddedAfterDataSectionInReoffer) {
1113 auto caller = CreatePeerConnection();
1114 caller->CreateDataChannel("dc");
1115 auto callee = CreatePeerConnection();
1116
1117 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1118
1119 caller->AddAudioTrack("a");
1120
1121 auto offer = caller->CreateOffer();
1122 auto contents = offer->description()->contents();
1123 ASSERT_EQ(2u, contents.size());
1124 EXPECT_EQ(cricket::MEDIA_TYPE_DATA, contents[0].media_description()->type());
1125 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, contents[1].media_description()->type());
1126}
1127
Steve Antondcc3c022017-12-22 16:02:54 -08001128// Tests for MID properties.
1129
1130static void RenameSection(size_t mline_index,
1131 const std::string& new_mid,
1132 SessionDescriptionInterface* sdesc) {
1133 cricket::SessionDescription* desc = sdesc->description();
1134 std::string old_mid = desc->contents()[mline_index].name;
1135 desc->contents()[mline_index].name = new_mid;
1136 desc->transport_infos()[mline_index].content_name = new_mid;
1137 const cricket::ContentGroup* bundle =
1138 desc->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1139 if (bundle) {
1140 cricket::ContentGroup new_bundle = *bundle;
1141 if (new_bundle.RemoveContentName(old_mid)) {
1142 new_bundle.AddContentName(new_mid);
1143 }
1144 desc->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1145 desc->AddGroup(new_bundle);
1146 }
1147}
1148
1149// Test that two PeerConnections can have a successful offer/answer exchange if
1150// the MIDs are changed from the defaults.
1151TEST_F(PeerConnectionJsepTest, OfferAnswerWithChangedMids) {
1152 constexpr char kFirstMid[] = "nondefaultmid";
1153 constexpr char kSecondMid[] = "randommid";
1154
1155 auto caller = CreatePeerConnection();
1156 caller->AddAudioTrack("a");
1157 caller->AddAudioTrack("b");
1158 auto callee = CreatePeerConnection();
1159
1160 auto offer = caller->CreateOffer();
1161 RenameSection(0, kFirstMid, offer.get());
1162 RenameSection(1, kSecondMid, offer.get());
1163
1164 ASSERT_TRUE(
1165 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
1166 auto caller_transceivers = caller->pc()->GetTransceivers();
1167 EXPECT_EQ(kFirstMid, caller_transceivers[0]->mid());
1168 EXPECT_EQ(kSecondMid, caller_transceivers[1]->mid());
1169
1170 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1171 auto callee_transceivers = callee->pc()->GetTransceivers();
1172 EXPECT_EQ(kFirstMid, callee_transceivers[0]->mid());
1173 EXPECT_EQ(kSecondMid, callee_transceivers[1]->mid());
1174
1175 auto answer = callee->CreateAnswer();
1176 auto answer_contents = answer->description()->contents();
1177 EXPECT_EQ(kFirstMid, answer_contents[0].name);
1178 EXPECT_EQ(kSecondMid, answer_contents[1].name);
1179
1180 ASSERT_TRUE(
1181 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
1182 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
1183}
1184
1185// Test that CreateOffer will generate a MID that is not already used if the
1186// default it would have picked is already taken. This is tested by using a
1187// third PeerConnection to determine what the default would be for the second
1188// media section then setting that as the first media section's MID.
1189TEST_F(PeerConnectionJsepTest, CreateOfferGeneratesUniqueMidIfAlreadyTaken) {
1190 // First, find what the default MID is for the second media section.
1191 auto pc = CreatePeerConnection();
1192 pc->AddAudioTrack("a");
1193 pc->AddAudioTrack("b");
1194 auto default_offer = pc->CreateOffer();
1195 std::string default_second_mid =
1196 default_offer->description()->contents()[1].name;
1197
1198 // Now, do an offer/answer with one track which has the MID set to the default
1199 // second MID.
1200 auto caller = CreatePeerConnection();
1201 caller->AddAudioTrack("a");
1202 auto callee = CreatePeerConnection();
1203
1204 auto offer = caller->CreateOffer();
1205 RenameSection(0, default_second_mid, offer.get());
1206
1207 ASSERT_TRUE(
1208 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
1209 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1210 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1211
1212 // Add a second track and ensure that the MID is different.
1213 caller->AddAudioTrack("b");
1214
1215 auto reoffer = caller->CreateOffer();
1216 auto reoffer_contents = reoffer->description()->contents();
1217 EXPECT_EQ(default_second_mid, reoffer_contents[0].name);
1218 EXPECT_NE(reoffer_contents[0].name, reoffer_contents[1].name);
1219}
1220
Steve Antonfa2260d2017-12-28 16:38:23 -08001221// Test that if an audio or video section has the default data section MID, then
1222// CreateOffer will generate a unique MID for the newly added data section.
1223TEST_F(PeerConnectionJsepTest,
1224 CreateOfferGeneratesUniqueMidForDataSectionIfAlreadyTaken) {
1225 // First, find what the default MID is for the data channel.
1226 auto pc = CreatePeerConnection();
1227 pc->CreateDataChannel("dc");
1228 auto default_offer = pc->CreateOffer();
1229 std::string default_data_mid =
1230 default_offer->description()->contents()[0].name;
1231
1232 // Now do an offer/answer with one audio track which has a MID set to the
1233 // default data MID.
1234 auto caller = CreatePeerConnection();
1235 caller->AddAudioTrack("a");
1236 auto callee = CreatePeerConnection();
1237
1238 auto offer = caller->CreateOffer();
1239 RenameSection(0, default_data_mid, offer.get());
1240
1241 ASSERT_TRUE(
1242 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
1243 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1244 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1245
1246 // Add a data channel and ensure that the MID is different.
1247 caller->CreateDataChannel("dc");
1248
1249 auto reoffer = caller->CreateOffer();
1250 auto reoffer_contents = reoffer->description()->contents();
1251 EXPECT_EQ(default_data_mid, reoffer_contents[0].name);
1252 EXPECT_NE(reoffer_contents[0].name, reoffer_contents[1].name);
1253}
1254
Steve Antondcc3c022017-12-22 16:02:54 -08001255// Test that a reoffer initiated by the callee adds a new track to the caller.
1256TEST_F(PeerConnectionJsepTest, CalleeDoesReoffer) {
1257 auto caller = CreatePeerConnection();
1258 caller->AddAudioTrack("a");
1259 auto callee = CreatePeerConnection();
1260 callee->AddAudioTrack("a");
1261 callee->AddVideoTrack("v");
1262
1263 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1264
1265 EXPECT_EQ(1u, caller->pc()->GetTransceivers().size());
1266 EXPECT_EQ(2u, callee->pc()->GetTransceivers().size());
1267
1268 ASSERT_TRUE(callee->ExchangeOfferAnswerWith(caller.get()));
1269
1270 EXPECT_EQ(2u, caller->pc()->GetTransceivers().size());
1271 EXPECT_EQ(2u, callee->pc()->GetTransceivers().size());
1272}
1273
Steve Anton02ee47c2018-01-10 16:26:06 -08001274// Tests for MSID properties.
1275
1276// Test that adding a track with AddTrack results in an offer that signals the
1277// track's ID.
1278TEST_F(PeerConnectionJsepTest, AddingTrackWithAddTrackSpecifiesTrackId) {
1279 const std::string kTrackId = "audio_track";
1280
1281 auto caller = CreatePeerConnection();
1282 caller->AddAudioTrack(kTrackId);
1283
1284 auto offer = caller->CreateOffer();
1285 auto contents = offer->description()->contents();
1286 ASSERT_EQ(1u, contents.size());
1287 auto streams = contents[0].media_description()->streams();
1288 ASSERT_EQ(1u, streams.size());
1289 EXPECT_EQ(kTrackId, streams[0].id);
1290}
1291
1292// Test that adding a track by calling AddTransceiver then SetTrack results in
1293// an offer that does not signal the track's ID and signals a random ID.
1294TEST_F(PeerConnectionJsepTest,
1295 AddingTrackWithAddTransceiverSpecifiesRandomTrackId) {
1296 const std::string kTrackId = "audio_track";
1297
1298 auto caller = CreatePeerConnection();
1299 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1300 transceiver->sender()->SetTrack(caller->CreateAudioTrack(kTrackId));
1301
1302 auto offer = caller->CreateOffer();
1303 auto contents = offer->description()->contents();
1304 ASSERT_EQ(1u, contents.size());
1305 auto streams = contents[0].media_description()->streams();
1306 ASSERT_EQ(1u, streams.size());
1307 EXPECT_NE(kTrackId, streams[0].id);
1308}
1309
Steve Anton5f94aa22018-02-01 10:58:30 -08001310// Test that if the transceiver is recvonly or inactive, then no MSID
1311// information is included in the offer.
1312TEST_F(PeerConnectionJsepTest, NoMsidInOfferIfTransceiverDirectionHasNoSend) {
1313 auto caller = CreatePeerConnection();
1314
1315 RtpTransceiverInit init_recvonly;
1316 init_recvonly.direction = RtpTransceiverDirection::kRecvOnly;
1317 ASSERT_TRUE(caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init_recvonly));
1318
1319 RtpTransceiverInit init_inactive;
1320 init_inactive.direction = RtpTransceiverDirection::kInactive;
1321 ASSERT_TRUE(caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init_inactive));
1322
1323 auto offer = caller->CreateOffer();
1324 auto contents = offer->description()->contents();
1325 ASSERT_EQ(2u, contents.size());
1326 // MSID is specified in the first stream, so no streams means no MSID.
1327 EXPECT_EQ(0u, contents[0].media_description()->streams().size());
1328 EXPECT_EQ(0u, contents[1].media_description()->streams().size());
1329}
1330
1331// Test that if an answer negotiates transceiver directions of recvonly or
1332// inactive, then no MSID information is included in the answer.
1333TEST_F(PeerConnectionJsepTest, NoMsidInAnswerIfNoRespondingTracks) {
1334 auto caller = CreatePeerConnection();
1335 auto callee = CreatePeerConnection();
1336
1337 // recvonly transceiver will get negotiated to inactive since the callee has
1338 // no tracks to send in response.
1339 RtpTransceiverInit init_recvonly;
1340 init_recvonly.direction = RtpTransceiverDirection::kRecvOnly;
1341 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init_recvonly);
1342
1343 // sendrecv transceiver will get negotiated to recvonly since the callee has
1344 // no tracks to send in response.
1345 RtpTransceiverInit init_sendrecv;
1346 init_sendrecv.direction = RtpTransceiverDirection::kSendRecv;
1347 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init_sendrecv);
1348
1349 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1350
1351 auto answer = callee->CreateAnswer();
1352 auto contents = answer->description()->contents();
1353 ASSERT_EQ(2u, contents.size());
1354 // MSID is specified in the first stream, so no streams means no MSID.
1355 EXPECT_EQ(0u, contents[0].media_description()->streams().size());
1356 EXPECT_EQ(0u, contents[1].media_description()->streams().size());
1357}
1358
1359// Test that the MSID is included even if the transceiver direction has changed
1360// to inactive if the transceiver had previously sent media.
1361TEST_F(PeerConnectionJsepTest, IncludeMsidEvenIfDirectionHasChanged) {
1362 auto caller = CreatePeerConnection();
1363 caller->AddAudioTrack("audio");
1364 auto callee = CreatePeerConnection();
1365 callee->AddAudioTrack("audio");
1366
1367 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1368
1369 caller->pc()->GetTransceivers()[0]->SetDirection(
1370 RtpTransceiverDirection::kInactive);
1371
1372 // The transceiver direction on both sides will turn to inactive.
1373 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1374
1375 auto* offer = callee->pc()->remote_description();
1376 auto offer_contents = offer->description()->contents();
1377 ASSERT_EQ(1u, offer_contents.size());
1378 // MSID is specified in the first stream. If it is present, assume that MSID
1379 // is there.
1380 EXPECT_EQ(1u, offer_contents[0].media_description()->streams().size());
1381
1382 auto* answer = caller->pc()->remote_description();
1383 auto answer_contents = answer->description()->contents();
1384 ASSERT_EQ(1u, answer_contents.size());
1385 EXPECT_EQ(1u, answer_contents[0].media_description()->streams().size());
1386}
1387
1388// Test that stopping a RtpTransceiver will cause future offers to not include
1389// any MSID information for that section.
1390TEST_F(PeerConnectionJsepTest, RemoveMsidIfTransceiverStopped) {
1391 auto caller = CreatePeerConnection();
1392 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1393 auto callee = CreatePeerConnection();
1394
1395 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1396
1397 transceiver->Stop();
1398
1399 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1400
1401 auto* offer = callee->pc()->remote_description();
1402 auto offer_contents = offer->description()->contents();
1403 ASSERT_EQ(1u, offer_contents.size());
1404 // MSID is specified in the first stream, so no streams means no MSID.
1405 EXPECT_EQ(0u, offer_contents[0].media_description()->streams().size());
1406}
1407
Steve Anton02ee47c2018-01-10 16:26:06 -08001408// Test that the callee RtpReceiver created by a call to SetRemoteDescription
1409// has its ID set to the signaled track ID.
1410TEST_F(PeerConnectionJsepTest,
1411 RtpReceiverCreatedBySetRemoteDescriptionHasSignaledTrackId) {
1412 const std::string kTrackId = "audio_track";
1413
1414 auto caller = CreatePeerConnection();
1415 auto callee = CreatePeerConnection();
1416 caller->AddAudioTrack(kTrackId);
1417
1418 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1419
1420 ASSERT_EQ(1u, callee->pc()->GetReceivers().size());
1421 auto receiver = callee->pc()->GetReceivers()[0];
1422 EXPECT_EQ(kTrackId, receiver->id());
1423}
1424
1425// Test that if the callee RtpReceiver is reused by a call to
1426// SetRemoteDescription, its ID does not change.
1427TEST_F(PeerConnectionJsepTest,
1428 RtpReceiverCreatedBeforeSetRemoteDescriptionKeepsId) {
1429 const std::string kTrackId = "audio_track";
1430
1431 auto caller = CreatePeerConnection();
1432 auto callee = CreatePeerConnection();
1433 caller->AddAudioTrack(kTrackId);
1434 callee->AddAudioTrack("dummy_track");
1435
1436 ASSERT_EQ(1u, callee->pc()->GetReceivers().size());
1437 auto receiver = callee->pc()->GetReceivers()[0];
1438 std::string receiver_id = receiver->id();
1439
1440 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1441
1442 EXPECT_EQ(receiver_id, receiver->id());
1443}
1444
Steve Antonef65ef12018-01-10 17:15:20 -08001445// Test that setting a remote offer with one track that has no streams fires off
1446// the correct OnAddTrack event.
1447TEST_F(PeerConnectionJsepTest,
1448 SetRemoteOfferWithOneTrackNoStreamFiresOnAddTrack) {
1449 const std::string kTrackLabel = "audio_track";
1450
1451 auto caller = CreatePeerConnection();
1452 auto callee = CreatePeerConnection();
1453 ASSERT_TRUE(caller->AddAudioTrack(kTrackLabel));
1454
1455 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1456
Seth Hampson5b4f0752018-04-02 16:31:36 -07001457 const auto& track_events = callee->observer()->add_track_events_;
1458 ASSERT_EQ(1u, track_events.size());
1459 const auto& event = track_events[0];
1460 EXPECT_EQ(kTrackLabel, event.receiver->track()->id());
1461 EXPECT_EQ(0u, event.streams.size());
Steve Antonef65ef12018-01-10 17:15:20 -08001462}
1463
1464// Test that setting a remote offer with one track that has one stream fires off
1465// the correct OnAddTrack event.
1466TEST_F(PeerConnectionJsepTest,
1467 SetRemoteOfferWithOneTrackOneStreamFiresOnAddTrack) {
1468 const std::string kTrackLabel = "audio_track";
Seth Hampson845e8782018-03-02 11:34:10 -08001469 const std::string kStreamId = "audio_stream";
Steve Antonef65ef12018-01-10 17:15:20 -08001470
1471 auto caller = CreatePeerConnection();
1472 auto callee = CreatePeerConnection();
Seth Hampson845e8782018-03-02 11:34:10 -08001473 ASSERT_TRUE(caller->AddAudioTrack(kTrackLabel, {kStreamId}));
Steve Antonef65ef12018-01-10 17:15:20 -08001474
1475 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1476
1477 const auto& track_events = callee->observer()->add_track_events_;
1478 ASSERT_EQ(1u, track_events.size());
1479 const auto& event = track_events[0];
1480 ASSERT_EQ(1u, event.streams.size());
1481 auto stream = event.streams[0];
Seth Hampson13b8bad2018-03-13 16:05:28 -07001482 EXPECT_EQ(kStreamId, stream->id());
Steve Antonef65ef12018-01-10 17:15:20 -08001483 EXPECT_THAT(track_events[0].snapshotted_stream_tracks.at(stream),
1484 ElementsAre(event.receiver->track()));
1485 EXPECT_EQ(event.receiver->streams(), track_events[0].streams);
1486}
1487
1488// Test that setting a remote offer with two tracks that share the same stream
1489// fires off two OnAddTrack events, both with the same stream that has both
1490// tracks present at the time of firing. This is to ensure that track events are
1491// not fired until SetRemoteDescription has finished processing all the media
1492// sections.
1493TEST_F(PeerConnectionJsepTest,
1494 SetRemoteOfferWithTwoTracksSameStreamFiresOnAddTrack) {
1495 const std::string kTrack1Label = "audio_track1";
1496 const std::string kTrack2Label = "audio_track2";
Seth Hampson845e8782018-03-02 11:34:10 -08001497 const std::string kSharedStreamId = "stream";
Steve Antonef65ef12018-01-10 17:15:20 -08001498
1499 auto caller = CreatePeerConnection();
1500 auto callee = CreatePeerConnection();
Seth Hampson845e8782018-03-02 11:34:10 -08001501 ASSERT_TRUE(caller->AddAudioTrack(kTrack1Label, {kSharedStreamId}));
1502 ASSERT_TRUE(caller->AddAudioTrack(kTrack2Label, {kSharedStreamId}));
Steve Antonef65ef12018-01-10 17:15:20 -08001503
1504 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1505
1506 const auto& track_events = callee->observer()->add_track_events_;
1507 ASSERT_EQ(2u, track_events.size());
1508 const auto& event1 = track_events[0];
1509 const auto& event2 = track_events[1];
1510 ASSERT_EQ(1u, event1.streams.size());
1511 auto stream = event1.streams[0];
1512 ASSERT_THAT(event2.streams, ElementsAre(stream));
1513 auto track1 = event1.receiver->track();
1514 auto track2 = event2.receiver->track();
1515 EXPECT_THAT(event1.snapshotted_stream_tracks.at(stream),
1516 UnorderedElementsAre(track1, track2));
1517 EXPECT_THAT(event2.snapshotted_stream_tracks.at(stream),
1518 UnorderedElementsAre(track1, track2));
1519}
1520
Seth Hampson5b4f0752018-04-02 16:31:36 -07001521// Test that setting a remote offer with one track that has two streams fires
1522// off the correct OnAddTrack event.
1523TEST_F(PeerConnectionJsepTest,
1524 SetRemoteOfferWithOneTrackTwoStreamFiresOnAddTrack) {
1525 const std::string kTrackLabel = "audio_track";
1526 const std::string kStreamId1 = "audio_stream1";
1527 const std::string kStreamId2 = "audio_stream2";
1528
1529 auto caller = CreatePeerConnection();
1530 auto callee = CreatePeerConnection();
1531 ASSERT_TRUE(caller->AddAudioTrack(kTrackLabel, {kStreamId1, kStreamId2}));
1532
1533 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1534
1535 const auto& track_events = callee->observer()->add_track_events_;
1536 ASSERT_EQ(1u, track_events.size());
1537 const auto& event = track_events[0];
1538 ASSERT_EQ(2u, event.streams.size());
1539 EXPECT_EQ(kStreamId1, event.streams[0]->id());
1540 EXPECT_EQ(kStreamId2, event.streams[1]->id());
1541}
Steve Antonef65ef12018-01-10 17:15:20 -08001542
Steve Anton54b84072018-02-20 15:19:52 -08001543// Test that if an RtpTransceiver with a current_direction set is stopped, then
1544// current_direction is changed to null.
1545TEST_F(PeerConnectionJsepTest, CurrentDirectionResetWhenRtpTransceiverStopped) {
1546 auto caller = CreatePeerConnection();
1547 auto callee = CreatePeerConnection();
1548
1549 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1550
1551 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1552
1553 ASSERT_TRUE(transceiver->current_direction());
1554 transceiver->Stop();
1555 EXPECT_FALSE(transceiver->current_direction());
1556}
1557
Steve Antonba42e992018-04-09 14:10:01 -07001558// Test that you can't set an answer on a PeerConnection before setting the
1559// offer.
Harald Alvestrand5081c0c2018-03-09 15:18:03 +01001560TEST_F(PeerConnectionJsepTest, AnswerBeforeOfferFails) {
1561 auto caller = CreatePeerConnection();
1562 auto callee = CreatePeerConnection();
Harald Alvestrand5081c0c2018-03-09 15:18:03 +01001563 caller->AddAudioTrack("audio");
Steve Antonba42e992018-04-09 14:10:01 -07001564
1565 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1566
1567 RTCError error;
1568 ASSERT_FALSE(caller->SetRemoteDescription(callee->CreateAnswer(), &error));
1569 EXPECT_EQ(RTCErrorType::INVALID_STATE, error.type());
1570}
1571
1572// Test that a Unified Plan PeerConnection fails to set a Plan B offer if it has
1573// two video tracks.
1574TEST_F(PeerConnectionJsepTest, TwoVideoPlanBToUnifiedPlanFails) {
1575 RTCConfiguration config_planb;
1576 config_planb.sdp_semantics = SdpSemantics::kPlanB;
1577 auto caller = CreatePeerConnection(config_planb);
1578 auto callee = CreatePeerConnection();
1579 caller->AddVideoTrack("video1");
1580 caller->AddVideoTrack("video2");
1581
1582 RTCError error;
1583 ASSERT_FALSE(callee->SetRemoteDescription(caller->CreateOffer(), &error));
1584 EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, error.type());
1585}
1586
1587// Test that a Unified Plan PeerConnection fails to set a Plan B answer if it
1588// has two video tracks.
1589TEST_F(PeerConnectionJsepTest, OneVideoUnifiedPlanToTwoVideoPlanBFails) {
1590 auto caller = CreatePeerConnection();
1591 RTCConfiguration config_planb;
1592 config_planb.sdp_semantics = SdpSemantics::kPlanB;
1593 auto callee = CreatePeerConnection(config_planb);
1594 caller->AddVideoTrack("video");
1595 callee->AddVideoTrack("video1");
1596 callee->AddVideoTrack("video2");
1597
1598 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1599
1600 RTCError error;
1601 ASSERT_FALSE(caller->SetRemoteDescription(caller->CreateAnswer(), &error));
1602 EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, error.type());
Harald Alvestrand5081c0c2018-03-09 15:18:03 +01001603}
1604
Steve Anton06817cd2018-12-18 15:55:30 -08001605// Removes the RTP header extension associated with the given URI from the media
1606// description.
1607static void RemoveRtpHeaderExtensionByUri(
1608 MediaContentDescription* media_description,
1609 absl::string_view uri) {
1610 std::vector<RtpExtension> header_extensions =
1611 media_description->rtp_header_extensions();
1612 header_extensions.erase(std::remove_if(
1613 header_extensions.begin(), header_extensions.end(),
1614 [uri](const RtpExtension& extension) { return extension.uri == uri; }));
1615 media_description->set_rtp_header_extensions(header_extensions);
1616}
1617
1618// Transforms a session description to emulate a legacy endpoint which does not
1619// support a=mid, BUNDLE, and the MID header extension.
1620static void ClearMids(SessionDescriptionInterface* sdesc) {
1621 cricket::SessionDescription* desc = sdesc->description();
1622 desc->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1623 cricket::ContentInfo* audio_content = cricket::GetFirstAudioContent(desc);
1624 if (audio_content) {
1625 desc->GetTransportInfoByName(audio_content->name)->content_name = "";
1626 audio_content->name = "";
1627 RemoveRtpHeaderExtensionByUri(audio_content->media_description(),
1628 RtpExtension::kMidUri);
1629 }
1630 cricket::ContentInfo* video_content = cricket::GetFirstVideoContent(desc);
1631 if (video_content) {
1632 desc->GetTransportInfoByName(video_content->name)->content_name = "";
1633 video_content->name = "";
1634 RemoveRtpHeaderExtensionByUri(video_content->media_description(),
1635 RtpExtension::kMidUri);
1636 }
1637}
1638
1639// Test that negotiation works with legacy endpoints which do not support a=mid.
1640TEST_F(PeerConnectionJsepTest, LegacyNoMidAudioOnlyOffer) {
1641 auto caller = CreatePeerConnection();
1642 caller->AddAudioTrack("audio");
1643 auto callee = CreatePeerConnection();
1644 callee->AddAudioTrack("audio");
1645
1646 auto offer = caller->CreateOffer();
1647 ClearMids(offer.get());
1648
1649 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1650 EXPECT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1651}
1652TEST_F(PeerConnectionJsepTest, LegacyNoMidAudioVideoOffer) {
1653 auto caller = CreatePeerConnection();
1654 caller->AddAudioTrack("audio");
1655 caller->AddVideoTrack("video");
1656 auto callee = CreatePeerConnection();
1657 callee->AddAudioTrack("audio");
1658 callee->AddVideoTrack("video");
1659
1660 auto offer = caller->CreateOffer();
1661 ClearMids(offer.get());
1662
1663 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1664 EXPECT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1665}
1666TEST_F(PeerConnectionJsepTest, LegacyNoMidAudioOnlyAnswer) {
1667 auto caller = CreatePeerConnection();
1668 caller->AddAudioTrack("audio");
1669 auto callee = CreatePeerConnection();
1670 callee->AddAudioTrack("audio");
1671
1672 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1673
1674 auto answer = callee->CreateAnswer();
1675 ClearMids(answer.get());
1676
1677 EXPECT_TRUE(caller->SetRemoteDescription(std::move(answer)));
1678}
1679TEST_F(PeerConnectionJsepTest, LegacyNoMidAudioVideoAnswer) {
1680 auto caller = CreatePeerConnection();
1681 caller->AddAudioTrack("audio");
1682 caller->AddVideoTrack("video");
1683 auto callee = CreatePeerConnection();
1684 callee->AddAudioTrack("audio");
1685 callee->AddVideoTrack("video");
1686
1687 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1688
1689 auto answer = callee->CreateAnswer();
1690 ClearMids(answer.get());
1691
1692 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
1693}
1694
Steve Antond7180cc2019-02-07 10:44:53 -08001695// Test that negotiation works with legacy endpoints which do not support a=mid
1696// when setting two remote descriptions without setting a local description in
1697// between.
1698TEST_F(PeerConnectionJsepTest, LegacyNoMidTwoRemoteOffers) {
1699 auto caller = CreatePeerConnection();
1700 caller->AddAudioTrack("audio");
1701 auto callee = CreatePeerConnection();
1702 callee->AddAudioTrack("audio");
1703
1704 auto offer = caller->CreateOffer();
1705 ClearMids(offer.get());
1706
1707 ASSERT_TRUE(
1708 callee->SetRemoteDescription(CloneSessionDescription(offer.get())));
1709 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1710 EXPECT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1711}
1712
Steve Antonceac0152018-12-19 11:32:20 -08001713// Test that SetLocalDescription fails if a=mid lines are missing.
1714TEST_F(PeerConnectionJsepTest, SetLocalDescriptionFailsMissingMid) {
1715 auto caller = CreatePeerConnection();
1716 caller->AddAudioTrack("audio");
1717
1718 auto offer = caller->CreateOffer();
1719 ClearMids(offer.get());
1720
1721 std::string error;
1722 ASSERT_FALSE(caller->SetLocalDescription(std::move(offer), &error));
1723 EXPECT_EQ(
1724 "Failed to set local offer sdp: A media section is missing a MID "
1725 "attribute.",
1726 error);
1727}
1728
Steve Antondcc3c022017-12-22 16:02:54 -08001729} // namespace webrtc