blob: 6c51f01594276354cbbe49629bf14d17678a4557 [file] [log] [blame]
Steve Antonda6c0952017-10-23 11:41:54 -07001/*
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
Yves Gerey3e707812018-11-28 16:47:49 +010011#include <memory>
12#include <string>
13#include <type_traits>
14#include <utility>
15#include <vector>
Steve Antonda6c0952017-10-23 11:41:54 -070016
Yves Gerey3e707812018-11-28 16:47:49 +010017#include "absl/types/optional.h"
Steve Anton10542f22019-01-11 09:11:00 -080018#include "api/call/call_factory_interface.h"
Yves Gerey3e707812018-11-28 16:47:49 +010019#include "api/jsep.h"
Steve Anton10542f22019-01-11 09:11:00 -080020#include "api/media_types.h"
21#include "api/peer_connection_interface.h"
22#include "api/peer_connection_proxy.h"
Mirko Bonadeid9708072019-01-25 20:26:48 +010023#include "api/scoped_refptr.h"
Danil Chapovalov53d45ba2019-07-03 14:56:33 +020024#include "api/task_queue/default_task_queue_factory.h"
Yves Gerey3e707812018-11-28 16:47:49 +010025#include "media/base/codec.h"
Steve Anton10542f22019-01-11 09:11:00 -080026#include "media/base/fake_media_engine.h"
27#include "media/base/media_constants.h"
28#include "media/base/media_engine.h"
29#include "media/sctp/sctp_transport_internal.h"
30#include "p2p/base/p2p_constants.h"
31#include "p2p/base/port_allocator.h"
32#include "pc/media_session.h"
33#include "pc/peer_connection.h"
34#include "pc/peer_connection_factory.h"
35#include "pc/peer_connection_wrapper.h"
36#include "pc/sdp_utils.h"
37#include "pc/session_description.h"
38#include "pc/test/mock_peer_connection_observers.h"
Yves Gerey3e707812018-11-28 16:47:49 +010039#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080040#include "rtc_base/ref_counted_object.h"
41#include "rtc_base/rtc_certificate_generator.h"
Yves Gerey3e707812018-11-28 16:47:49 +010042#include "rtc_base/thread.h"
Harald Alvestrand4aa11922019-05-14 22:00:01 +020043#include "test/gmock.h"
Yves Gerey3e707812018-11-28 16:47:49 +010044#include "test/gtest.h"
Steve Antonda6c0952017-10-23 11:41:54 -070045#ifdef WEBRTC_ANDROID
Steve Anton10542f22019-01-11 09:11:00 -080046#include "pc/test/android_test_initializer.h"
Steve Antonda6c0952017-10-23 11:41:54 -070047#endif
Steve Anton10542f22019-01-11 09:11:00 -080048#include "rtc_base/virtual_socket_server.h"
Per Kjellander2bca0082020-08-28 09:15:15 +020049#include "test/pc/sctp/fake_sctp_transport.h"
Steve Antonda6c0952017-10-23 11:41:54 -070050
51namespace webrtc {
52
53using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
54using RTCOfferAnswerOptions = PeerConnectionInterface::RTCOfferAnswerOptions;
Harald Alvestrand4aa11922019-05-14 22:00:01 +020055using ::testing::HasSubstr;
56using ::testing::Not;
Steve Antonda6c0952017-10-23 11:41:54 -070057using ::testing::Values;
58
Bjorn Mellem175aa2e2018-11-08 11:23:22 -080059namespace {
60
Per Kjellander2bca0082020-08-28 09:15:15 +020061PeerConnectionFactoryDependencies CreatePeerConnectionFactoryDependencies() {
Bjorn Mellem175aa2e2018-11-08 11:23:22 -080062 PeerConnectionFactoryDependencies deps;
Per Kjellander2bca0082020-08-28 09:15:15 +020063 deps.network_thread = rtc::Thread::Current();
64 deps.worker_thread = rtc::Thread::Current();
65 deps.signaling_thread = rtc::Thread::Current();
Danil Chapovalov53d45ba2019-07-03 14:56:33 +020066 deps.task_queue_factory = CreateDefaultTaskQueueFactory();
Per Kjellander2bca0082020-08-28 09:15:15 +020067 deps.media_engine = std::make_unique<cricket::FakeMediaEngine>();
68 deps.call_factory = CreateCallFactory();
69 deps.sctp_factory = std::make_unique<FakeSctpTransportFactory>();
Bjorn Mellem175aa2e2018-11-08 11:23:22 -080070 return deps;
71}
72
73} // namespace
74
Steve Antonda6c0952017-10-23 11:41:54 -070075class PeerConnectionWrapperForDataChannelTest : public PeerConnectionWrapper {
76 public:
77 using PeerConnectionWrapper::PeerConnectionWrapper;
78
79 FakeSctpTransportFactory* sctp_transport_factory() {
80 return sctp_transport_factory_;
81 }
82
83 void set_sctp_transport_factory(
84 FakeSctpTransportFactory* sctp_transport_factory) {
85 sctp_transport_factory_ = sctp_transport_factory;
86 }
87
Harald Alvestrand1cb929f2020-02-05 12:07:33 +010088 absl::optional<std::string> sctp_mid() {
89 return GetInternalPeerConnection()->sctp_mid();
Steve Antonda6c0952017-10-23 11:41:54 -070090 }
91
Danil Chapovalov66cadcc2018-06-19 16:47:43 +020092 absl::optional<std::string> sctp_transport_name() {
Steve Antonda6c0952017-10-23 11:41:54 -070093 return GetInternalPeerConnection()->sctp_transport_name();
94 }
95
96 PeerConnection* GetInternalPeerConnection() {
Mirko Bonadeie97de912017-12-13 11:29:34 +010097 auto* pci =
98 static_cast<PeerConnectionProxyWithInternal<PeerConnectionInterface>*>(
99 pc());
100 return static_cast<PeerConnection*>(pci->internal());
Steve Antonda6c0952017-10-23 11:41:54 -0700101 }
102
103 private:
104 FakeSctpTransportFactory* sctp_transport_factory_ = nullptr;
105};
106
Steve Antondbf9d032018-01-19 15:23:40 -0800107class PeerConnectionDataChannelBaseTest : public ::testing::Test {
Steve Antonda6c0952017-10-23 11:41:54 -0700108 protected:
109 typedef std::unique_ptr<PeerConnectionWrapperForDataChannelTest> WrapperPtr;
110
Steve Antondbf9d032018-01-19 15:23:40 -0800111 explicit PeerConnectionDataChannelBaseTest(SdpSemantics sdp_semantics)
112 : vss_(new rtc::VirtualSocketServer()),
113 main_(vss_.get()),
114 sdp_semantics_(sdp_semantics) {
Steve Antonda6c0952017-10-23 11:41:54 -0700115#ifdef WEBRTC_ANDROID
116 InitializeAndroidObjects();
117#endif
118 }
119
120 WrapperPtr CreatePeerConnection() {
121 return CreatePeerConnection(RTCConfiguration());
122 }
123
124 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
125 return CreatePeerConnection(config,
126 PeerConnectionFactoryInterface::Options());
127 }
128
129 WrapperPtr CreatePeerConnection(
130 const RTCConfiguration& config,
131 const PeerConnectionFactoryInterface::Options factory_options) {
Per Kjellander2bca0082020-08-28 09:15:15 +0200132 auto factory_deps = CreatePeerConnectionFactoryDependencies();
133 FakeSctpTransportFactory* fake_sctp_transport_factory =
134 static_cast<FakeSctpTransportFactory*>(factory_deps.sctp_factory.get());
135 rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory =
136 CreateModularPeerConnectionFactory(std::move(factory_deps));
Steve Antonda6c0952017-10-23 11:41:54 -0700137 pc_factory->SetOptions(factory_options);
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200138 auto observer = std::make_unique<MockPeerConnectionObserver>();
Steve Antondbf9d032018-01-19 15:23:40 -0800139 RTCConfiguration modified_config = config;
140 modified_config.sdp_semantics = sdp_semantics_;
141 auto pc = pc_factory->CreatePeerConnection(modified_config, nullptr,
142 nullptr, observer.get());
Steve Antonda6c0952017-10-23 11:41:54 -0700143 if (!pc) {
144 return nullptr;
145 }
146
Yves Gerey4e933292018-10-31 15:36:05 +0100147 observer->SetPeerConnectionInterface(pc.get());
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200148 auto wrapper = std::make_unique<PeerConnectionWrapperForDataChannelTest>(
Steve Antonda6c0952017-10-23 11:41:54 -0700149 pc_factory, pc, std::move(observer));
Per Kjellander2bca0082020-08-28 09:15:15 +0200150 wrapper->set_sctp_transport_factory(fake_sctp_transport_factory);
Steve Antonda6c0952017-10-23 11:41:54 -0700151 return wrapper;
152 }
153
154 // Accepts the same arguments as CreatePeerConnection and adds a default data
155 // channel.
156 template <typename... Args>
157 WrapperPtr CreatePeerConnectionWithDataChannel(Args&&... args) {
158 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
159 if (!wrapper) {
160 return nullptr;
161 }
162 EXPECT_TRUE(wrapper->pc()->CreateDataChannel("dc", nullptr));
163 return wrapper;
164 }
165
166 // Changes the SCTP data channel port on the given session description.
167 void ChangeSctpPortOnDescription(cricket::SessionDescription* desc,
168 int port) {
Steve Antonda6c0952017-10-23 11:41:54 -0700169 auto* data_content = cricket::GetFirstDataContent(desc);
170 RTC_DCHECK(data_content);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200171 auto* data_desc = data_content->media_description()->as_sctp();
172 RTC_DCHECK(data_desc);
173 data_desc->set_port(port);
Steve Antonda6c0952017-10-23 11:41:54 -0700174 }
175
176 std::unique_ptr<rtc::VirtualSocketServer> vss_;
177 rtc::AutoSocketServerThread main_;
Steve Antondbf9d032018-01-19 15:23:40 -0800178 const SdpSemantics sdp_semantics_;
Steve Antonda6c0952017-10-23 11:41:54 -0700179};
180
Steve Antondbf9d032018-01-19 15:23:40 -0800181class PeerConnectionDataChannelTest
182 : public PeerConnectionDataChannelBaseTest,
183 public ::testing::WithParamInterface<SdpSemantics> {
184 protected:
185 PeerConnectionDataChannelTest()
186 : PeerConnectionDataChannelBaseTest(GetParam()) {}
187};
188
Steve Antonc8ff1602020-02-05 13:53:38 -0800189class PeerConnectionDataChannelUnifiedPlanTest
190 : public PeerConnectionDataChannelBaseTest {
191 protected:
192 PeerConnectionDataChannelUnifiedPlanTest()
193 : PeerConnectionDataChannelBaseTest(SdpSemantics::kUnifiedPlan) {}
194};
195
Steve Antondbf9d032018-01-19 15:23:40 -0800196TEST_P(PeerConnectionDataChannelTest,
Steve Antonda6c0952017-10-23 11:41:54 -0700197 NoSctpTransportCreatedIfRtpDataChannelEnabled) {
198 RTCConfiguration config;
199 config.enable_rtp_data_channel = true;
200 auto caller = CreatePeerConnectionWithDataChannel(config);
201
202 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
203 EXPECT_FALSE(caller->sctp_transport_factory()->last_fake_sctp_transport());
204}
205
Steve Antondbf9d032018-01-19 15:23:40 -0800206TEST_P(PeerConnectionDataChannelTest,
Steve Antonda6c0952017-10-23 11:41:54 -0700207 RtpDataChannelCreatedEvenIfSctpAvailable) {
208 RTCConfiguration config;
209 config.enable_rtp_data_channel = true;
210 PeerConnectionFactoryInterface::Options options;
211 options.disable_sctp_data_channels = false;
212 auto caller = CreatePeerConnectionWithDataChannel(config, options);
213
214 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
215 EXPECT_FALSE(caller->sctp_transport_factory()->last_fake_sctp_transport());
216}
217
Bjorn A Mellembc3eebc2019-09-23 14:53:54 -0700218TEST_P(PeerConnectionDataChannelTest, InternalSctpTransportDeletedOnTeardown) {
219 auto caller = CreatePeerConnectionWithDataChannel();
220
221 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
222 EXPECT_TRUE(caller->sctp_transport_factory()->last_fake_sctp_transport());
223
224 rtc::scoped_refptr<SctpTransportInterface> sctp_transport =
225 caller->GetInternalPeerConnection()->GetSctpTransport();
226
227 caller.reset();
228 EXPECT_EQ(static_cast<SctpTransport*>(sctp_transport.get())->internal(),
229 nullptr);
230}
231
Harald Alvestrand1cb929f2020-02-05 12:07:33 +0100232// Test that sctp_mid/sctp_transport_name (used for stats) are correct
Steve Antonda6c0952017-10-23 11:41:54 -0700233// before and after BUNDLE is negotiated.
Steve Antondbf9d032018-01-19 15:23:40 -0800234TEST_P(PeerConnectionDataChannelTest, SctpContentAndTransportNameSetCorrectly) {
Steve Antonda6c0952017-10-23 11:41:54 -0700235 auto caller = CreatePeerConnection();
236 auto callee = CreatePeerConnection();
237
238 // Initially these fields should be empty.
Harald Alvestrand1cb929f2020-02-05 12:07:33 +0100239 EXPECT_FALSE(caller->sctp_mid());
Steve Antonda6c0952017-10-23 11:41:54 -0700240 EXPECT_FALSE(caller->sctp_transport_name());
241
242 // Create offer with audio/video/data.
243 // Default bundle policy is "balanced", so data should be using its own
244 // transport.
245 caller->AddAudioTrack("a");
246 caller->AddVideoTrack("v");
247 caller->pc()->CreateDataChannel("dc", nullptr);
Steve Antondbf9d032018-01-19 15:23:40 -0800248
249 auto offer = caller->CreateOffer();
250 const auto& offer_contents = offer->description()->contents();
251 ASSERT_EQ(cricket::MEDIA_TYPE_AUDIO,
252 offer_contents[0].media_description()->type());
253 std::string audio_mid = offer_contents[0].name;
254 ASSERT_EQ(cricket::MEDIA_TYPE_DATA,
255 offer_contents[2].media_description()->type());
256 std::string data_mid = offer_contents[2].name;
257
258 ASSERT_TRUE(
259 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
260 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
Steve Antonda6c0952017-10-23 11:41:54 -0700261
Harald Alvestrand1cb929f2020-02-05 12:07:33 +0100262 ASSERT_TRUE(caller->sctp_mid());
263 EXPECT_EQ(data_mid, *caller->sctp_mid());
Steve Antonda6c0952017-10-23 11:41:54 -0700264 ASSERT_TRUE(caller->sctp_transport_name());
Steve Antondbf9d032018-01-19 15:23:40 -0800265 EXPECT_EQ(data_mid, *caller->sctp_transport_name());
Steve Antonda6c0952017-10-23 11:41:54 -0700266
267 // Create answer that finishes BUNDLE negotiation, which means everything
268 // should be bundled on the first transport (audio).
269 RTCOfferAnswerOptions options;
270 options.use_rtp_mux = true;
271 ASSERT_TRUE(
272 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
273
Harald Alvestrand1cb929f2020-02-05 12:07:33 +0100274 ASSERT_TRUE(caller->sctp_mid());
275 EXPECT_EQ(data_mid, *caller->sctp_mid());
Steve Antonda6c0952017-10-23 11:41:54 -0700276 ASSERT_TRUE(caller->sctp_transport_name());
Steve Antondbf9d032018-01-19 15:23:40 -0800277 EXPECT_EQ(audio_mid, *caller->sctp_transport_name());
Steve Antonda6c0952017-10-23 11:41:54 -0700278}
279
Steve Antondbf9d032018-01-19 15:23:40 -0800280TEST_P(PeerConnectionDataChannelTest,
Steve Antonda6c0952017-10-23 11:41:54 -0700281 CreateOfferWithNoDataChannelsGivesNoDataSection) {
282 auto caller = CreatePeerConnection();
283 auto offer = caller->CreateOffer();
284
285 EXPECT_FALSE(offer->description()->GetContentByName(cricket::CN_DATA));
286 EXPECT_FALSE(offer->description()->GetTransportInfoByName(cricket::CN_DATA));
287}
288
Steve Antondbf9d032018-01-19 15:23:40 -0800289TEST_P(PeerConnectionDataChannelTest,
Steve Antonda6c0952017-10-23 11:41:54 -0700290 CreateAnswerWithRemoteSctpDataChannelIncludesDataSection) {
291 auto caller = CreatePeerConnectionWithDataChannel();
292 auto callee = CreatePeerConnection();
293
294 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
295
296 auto answer = callee->CreateAnswer();
297 ASSERT_TRUE(answer);
Steve Antondbf9d032018-01-19 15:23:40 -0800298 auto* data_content = cricket::GetFirstDataContent(answer->description());
Steve Antonda6c0952017-10-23 11:41:54 -0700299 ASSERT_TRUE(data_content);
300 EXPECT_FALSE(data_content->rejected);
Steve Antondbf9d032018-01-19 15:23:40 -0800301 EXPECT_TRUE(
302 answer->description()->GetTransportInfoByName(data_content->name));
Steve Antonda6c0952017-10-23 11:41:54 -0700303}
304
Steve Antondbf9d032018-01-19 15:23:40 -0800305TEST_P(PeerConnectionDataChannelTest,
Steve Antonda6c0952017-10-23 11:41:54 -0700306 CreateDataChannelWithDtlsDisabledSucceeds) {
307 RTCConfiguration config;
308 config.enable_dtls_srtp.emplace(false);
309 auto caller = CreatePeerConnection();
310
311 EXPECT_TRUE(caller->pc()->CreateDataChannel("dc", nullptr));
312}
313
Steve Antondbf9d032018-01-19 15:23:40 -0800314TEST_P(PeerConnectionDataChannelTest, CreateDataChannelWithSctpDisabledFails) {
Steve Antonda6c0952017-10-23 11:41:54 -0700315 PeerConnectionFactoryInterface::Options options;
316 options.disable_sctp_data_channels = true;
317 auto caller = CreatePeerConnection(RTCConfiguration(), options);
318
319 EXPECT_FALSE(caller->pc()->CreateDataChannel("dc", nullptr));
320}
321
322// Test that if a callee has SCTP disabled and receives an offer with an SCTP
323// data channel, the data section is rejected and no SCTP transport is created
324// on the callee.
Steve Antondbf9d032018-01-19 15:23:40 -0800325TEST_P(PeerConnectionDataChannelTest,
Steve Antonda6c0952017-10-23 11:41:54 -0700326 DataSectionRejectedIfCalleeHasSctpDisabled) {
327 auto caller = CreatePeerConnectionWithDataChannel();
328 PeerConnectionFactoryInterface::Options options;
329 options.disable_sctp_data_channels = true;
330 auto callee = CreatePeerConnection(RTCConfiguration(), options);
331
332 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
333
334 EXPECT_FALSE(callee->sctp_transport_factory()->last_fake_sctp_transport());
335
336 auto answer = callee->CreateAnswer();
Steve Antondbf9d032018-01-19 15:23:40 -0800337 auto* data_content = cricket::GetFirstDataContent(answer->description());
Steve Antonda6c0952017-10-23 11:41:54 -0700338 ASSERT_TRUE(data_content);
339 EXPECT_TRUE(data_content->rejected);
340}
341
Steve Antondbf9d032018-01-19 15:23:40 -0800342TEST_P(PeerConnectionDataChannelTest, SctpPortPropagatedFromSdpToTransport) {
Steve Antonda6c0952017-10-23 11:41:54 -0700343 constexpr int kNewSendPort = 9998;
344 constexpr int kNewRecvPort = 7775;
345
346 auto caller = CreatePeerConnectionWithDataChannel();
347 auto callee = CreatePeerConnectionWithDataChannel();
348
349 auto offer = caller->CreateOffer();
350 ChangeSctpPortOnDescription(offer->description(), kNewSendPort);
351 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
352
353 auto answer = callee->CreateAnswer();
354 ChangeSctpPortOnDescription(answer->description(), kNewRecvPort);
355 ASSERT_TRUE(callee->SetLocalDescription(std::move(answer)));
356
357 auto* callee_transport =
358 callee->sctp_transport_factory()->last_fake_sctp_transport();
359 ASSERT_TRUE(callee_transport);
360 EXPECT_EQ(kNewSendPort, callee_transport->remote_port());
361 EXPECT_EQ(kNewRecvPort, callee_transport->local_port());
362}
363
Guido Urdanetacecf87f2019-05-31 10:17:38 +0000364TEST_P(PeerConnectionDataChannelTest, ModernSdpSyntaxByDefault) {
Harald Alvestrand4aa11922019-05-14 22:00:01 +0200365 PeerConnectionInterface::RTCOfferAnswerOptions options;
366 auto caller = CreatePeerConnectionWithDataChannel();
367 auto offer = caller->CreateOffer(options);
368 EXPECT_FALSE(cricket::GetFirstSctpDataContentDescription(offer->description())
369 ->use_sctpmap());
370 std::string sdp;
371 offer->ToString(&sdp);
372 RTC_LOG(LS_ERROR) << sdp;
373 EXPECT_THAT(sdp, HasSubstr(" UDP/DTLS/SCTP webrtc-datachannel"));
374 EXPECT_THAT(sdp, Not(HasSubstr("a=sctpmap:")));
375}
376
377TEST_P(PeerConnectionDataChannelTest, ObsoleteSdpSyntaxIfSet) {
378 PeerConnectionInterface::RTCOfferAnswerOptions options;
379 options.use_obsolete_sctp_sdp = true;
380 auto caller = CreatePeerConnectionWithDataChannel();
381 auto offer = caller->CreateOffer(options);
382 EXPECT_TRUE(cricket::GetFirstSctpDataContentDescription(offer->description())
383 ->use_sctpmap());
384 std::string sdp;
385 offer->ToString(&sdp);
386 EXPECT_THAT(sdp, Not(HasSubstr(" UDP/DTLS/SCTP webrtc-datachannel")));
387 EXPECT_THAT(sdp, HasSubstr("a=sctpmap:"));
388}
389
Mirko Bonadeic84f6612019-01-31 12:20:57 +0100390INSTANTIATE_TEST_SUITE_P(PeerConnectionDataChannelTest,
391 PeerConnectionDataChannelTest,
392 Values(SdpSemantics::kPlanB,
393 SdpSemantics::kUnifiedPlan));
Steve Antondbf9d032018-01-19 15:23:40 -0800394
Steve Antonc8ff1602020-02-05 13:53:38 -0800395TEST_F(PeerConnectionDataChannelUnifiedPlanTest,
396 ReOfferAfterPeerRejectsDataChannel) {
397 auto caller = CreatePeerConnectionWithDataChannel();
398 PeerConnectionFactoryInterface::Options options;
399 options.disable_sctp_data_channels = true;
400 auto callee = CreatePeerConnection(RTCConfiguration(), options);
401
402 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
403
404 auto offer = caller->CreateOffer();
405 ASSERT_TRUE(offer);
406 const auto& contents = offer->description()->contents();
407 ASSERT_EQ(1u, contents.size());
408 EXPECT_TRUE(contents[0].rejected);
409
410 ASSERT_TRUE(
411 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
412 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
413
414 auto answer = callee->CreateAnswerAndSetAsLocal();
415 ASSERT_TRUE(answer);
416 EXPECT_TRUE(caller->SetRemoteDescription(std::move(answer)));
417}
418
Steve Antonda6c0952017-10-23 11:41:54 -0700419} // namespace webrtc