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