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