blob: 1d7bb9211eb098f26dd819c6d28eaa7b7337ebf7 [file] [log] [blame]
wu@webrtc.org364f2042013-11-20 21:49:41 +00001/*
2 * libjingle
jlmiller@webrtc.org5f93d0a2015-01-20 21:36:13 +00003 * Copyright 2013 Google Inc.
wu@webrtc.org364f2042013-11-20 21:49:41 +00004 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
buildbot@webrtc.orga09a9992014-08-13 17:26:08 +000028#include "talk/app/webrtc/test/peerconnectiontestwrapper.h"
henrike@webrtc.orgd968dd02014-08-13 18:39:43 +000029#include "talk/app/webrtc/test/mockpeerconnectionobservers.h"
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000030#include "webrtc/base/gunit.h"
31#include "webrtc/base/logging.h"
32#include "webrtc/base/ssladapter.h"
33#include "webrtc/base/sslstreamadapter.h"
34#include "webrtc/base/stringencode.h"
35#include "webrtc/base/stringutils.h"
wu@webrtc.org364f2042013-11-20 21:49:41 +000036
jiayl@webrtc.org1a6c6282014-06-12 21:59:29 +000037#define MAYBE_SKIP_TEST(feature) \
38 if (!(feature())) { \
39 LOG(LS_INFO) << "Feature disabled... skipping"; \
40 return; \
41 }
42
43using webrtc::DataChannelInterface;
wu@webrtc.org364f2042013-11-20 21:49:41 +000044using webrtc::FakeConstraints;
45using webrtc::MediaConstraintsInterface;
46using webrtc::MediaStreamInterface;
47using webrtc::PeerConnectionInterface;
48
49namespace {
50
jiayl@webrtc.org1a6c6282014-06-12 21:59:29 +000051const size_t kMaxWait = 10000;
wu@webrtc.org364f2042013-11-20 21:49:41 +000052
53void RemoveLinesFromSdp(const std::string& line_start,
54 std::string* sdp) {
55 const char kSdpLineEnd[] = "\r\n";
56 size_t ssrc_pos = 0;
57 while ((ssrc_pos = sdp->find(line_start, ssrc_pos)) !=
58 std::string::npos) {
59 size_t end_ssrc = sdp->find(kSdpLineEnd, ssrc_pos);
60 sdp->erase(ssrc_pos, end_ssrc - ssrc_pos + strlen(kSdpLineEnd));
61 }
62}
63
64// Add |newlines| to the |message| after |line|.
65void InjectAfter(const std::string& line,
66 const std::string& newlines,
67 std::string* message) {
68 const std::string tmp = line + newlines;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000069 rtc::replace_substrs(line.c_str(), line.length(),
wu@webrtc.org364f2042013-11-20 21:49:41 +000070 tmp.c_str(), tmp.length(), message);
71}
72
73void Replace(const std::string& line,
74 const std::string& newlines,
75 std::string* message) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000076 rtc::replace_substrs(line.c_str(), line.length(),
wu@webrtc.org364f2042013-11-20 21:49:41 +000077 newlines.c_str(), newlines.length(), message);
78}
79
80void UseExternalSdes(std::string* sdp) {
81 // Remove current crypto specification.
82 RemoveLinesFromSdp("a=crypto", sdp);
83 RemoveLinesFromSdp("a=fingerprint", sdp);
84 // Add external crypto.
85 const char kAudioSdes[] =
86 "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
87 "inline:PS1uQCVeeCFCanVmcjkpPywjNWhcYD0mXXtxaVBR\r\n";
88 const char kVideoSdes[] =
89 "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
90 "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj\r\n";
91 const char kDataSdes[] =
92 "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
93 "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj\r\n";
94 InjectAfter("a=mid:audio\r\n", kAudioSdes, sdp);
95 InjectAfter("a=mid:video\r\n", kVideoSdes, sdp);
96 InjectAfter("a=mid:data\r\n", kDataSdes, sdp);
97}
98
wu@webrtc.org364f2042013-11-20 21:49:41 +000099void RemoveBundle(std::string* sdp) {
100 RemoveLinesFromSdp("a=group:BUNDLE", sdp);
101}
102
103} // namespace
104
105class PeerConnectionEndToEndTest
106 : public sigslot::has_slots<>,
107 public testing::Test {
108 public:
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000109 typedef std::vector<rtc::scoped_refptr<DataChannelInterface> >
jiayl@webrtc.org1a6c6282014-06-12 21:59:29 +0000110 DataChannelList;
111
wu@webrtc.org364f2042013-11-20 21:49:41 +0000112 PeerConnectionEndToEndTest()
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000113 : caller_(new rtc::RefCountedObject<PeerConnectionTestWrapper>(
wu@webrtc.org364f2042013-11-20 21:49:41 +0000114 "caller")),
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000115 callee_(new rtc::RefCountedObject<PeerConnectionTestWrapper>(
wu@webrtc.org364f2042013-11-20 21:49:41 +0000116 "callee")) {
wu@webrtc.org364f2042013-11-20 21:49:41 +0000117 }
118
119 void CreatePcs() {
120 CreatePcs(NULL);
121 }
122
123 void CreatePcs(const MediaConstraintsInterface* pc_constraints) {
124 EXPECT_TRUE(caller_->CreatePc(pc_constraints));
125 EXPECT_TRUE(callee_->CreatePc(pc_constraints));
126 PeerConnectionTestWrapper::Connect(caller_.get(), callee_.get());
jiayl@webrtc.org1a6c6282014-06-12 21:59:29 +0000127
128 caller_->SignalOnDataChannel.connect(
129 this, &PeerConnectionEndToEndTest::OnCallerAddedDataChanel);
130 callee_->SignalOnDataChannel.connect(
131 this, &PeerConnectionEndToEndTest::OnCalleeAddedDataChannel);
wu@webrtc.org364f2042013-11-20 21:49:41 +0000132 }
133
134 void GetAndAddUserMedia() {
135 FakeConstraints audio_constraints;
136 FakeConstraints video_constraints;
137 GetAndAddUserMedia(true, audio_constraints, true, video_constraints);
138 }
139
140 void GetAndAddUserMedia(bool audio, FakeConstraints audio_constraints,
141 bool video, FakeConstraints video_constraints) {
142 caller_->GetAndAddUserMedia(audio, audio_constraints,
143 video, video_constraints);
144 callee_->GetAndAddUserMedia(audio, audio_constraints,
145 video, video_constraints);
146 }
147
148 void Negotiate() {
149 caller_->CreateOffer(NULL);
150 }
151
152 void WaitForCallEstablished() {
153 caller_->WaitForCallEstablished();
154 callee_->WaitForCallEstablished();
155 }
156
jiayl@webrtc.org1a6c6282014-06-12 21:59:29 +0000157 void WaitForConnection() {
158 caller_->WaitForConnection();
159 callee_->WaitForConnection();
160 }
161
jiayl@webrtc.org1a6c6282014-06-12 21:59:29 +0000162 void OnCallerAddedDataChanel(DataChannelInterface* dc) {
163 caller_signaled_data_channels_.push_back(dc);
164 }
165
166 void OnCalleeAddedDataChannel(DataChannelInterface* dc) {
167 callee_signaled_data_channels_.push_back(dc);
168 }
169
170 // Tests that |dc1| and |dc2| can send to and receive from each other.
171 void TestDataChannelSendAndReceive(
172 DataChannelInterface* dc1, DataChannelInterface* dc2) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000173 rtc::scoped_ptr<webrtc::MockDataChannelObserver> dc1_observer(
jiayl@webrtc.org1a6c6282014-06-12 21:59:29 +0000174 new webrtc::MockDataChannelObserver(dc1));
175
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000176 rtc::scoped_ptr<webrtc::MockDataChannelObserver> dc2_observer(
jiayl@webrtc.org1a6c6282014-06-12 21:59:29 +0000177 new webrtc::MockDataChannelObserver(dc2));
178
179 static const std::string kDummyData = "abcdefg";
180 webrtc::DataBuffer buffer(kDummyData);
181 EXPECT_TRUE(dc1->Send(buffer));
182 EXPECT_EQ_WAIT(kDummyData, dc2_observer->last_message(), kMaxWait);
183
184 EXPECT_TRUE(dc2->Send(buffer));
185 EXPECT_EQ_WAIT(kDummyData, dc1_observer->last_message(), kMaxWait);
186
187 EXPECT_EQ(1U, dc1_observer->received_message_count());
188 EXPECT_EQ(1U, dc2_observer->received_message_count());
189 }
190
191 void WaitForDataChannelsToOpen(DataChannelInterface* local_dc,
192 const DataChannelList& remote_dc_list,
193 size_t remote_dc_index) {
194 EXPECT_EQ_WAIT(DataChannelInterface::kOpen, local_dc->state(), kMaxWait);
195
196 EXPECT_TRUE_WAIT(remote_dc_list.size() > remote_dc_index, kMaxWait);
197 EXPECT_EQ_WAIT(DataChannelInterface::kOpen,
198 remote_dc_list[remote_dc_index]->state(),
199 kMaxWait);
200 EXPECT_EQ(local_dc->id(), remote_dc_list[remote_dc_index]->id());
201 }
202
203 void CloseDataChannels(DataChannelInterface* local_dc,
204 const DataChannelList& remote_dc_list,
205 size_t remote_dc_index) {
206 local_dc->Close();
207 EXPECT_EQ_WAIT(DataChannelInterface::kClosed, local_dc->state(), kMaxWait);
208 EXPECT_EQ_WAIT(DataChannelInterface::kClosed,
209 remote_dc_list[remote_dc_index]->state(),
210 kMaxWait);
211 }
212
wu@webrtc.org364f2042013-11-20 21:49:41 +0000213 protected:
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000214 rtc::scoped_refptr<PeerConnectionTestWrapper> caller_;
215 rtc::scoped_refptr<PeerConnectionTestWrapper> callee_;
jiayl@webrtc.org1a6c6282014-06-12 21:59:29 +0000216 DataChannelList caller_signaled_data_channels_;
217 DataChannelList callee_signaled_data_channels_;
wu@webrtc.org364f2042013-11-20 21:49:41 +0000218};
219
kjellander@webrtc.org70c0e292015-11-30 21:45:35 +0100220// Disabled for TSan v2, see
221// https://bugs.chromium.org/p/webrtc/issues/detail?id=4719 for details.
kjellander@webrtc.org3c28d0d2015-12-02 22:53:26 +0100222// Disabled for Mac, see
223// https://bugs.chromium.org/p/webrtc/issues/detail?id=5231 for details.
224#if !defined(THREAD_SANITIZER) && !defined(WEBRTC_MAC)
deadbeefee8c6d32015-08-13 14:27:18 -0700225TEST_F(PeerConnectionEndToEndTest, Call) {
wu@webrtc.org364f2042013-11-20 21:49:41 +0000226 CreatePcs();
227 GetAndAddUserMedia();
228 Negotiate();
229 WaitForCallEstablished();
230}
kjellander@webrtc.org3c28d0d2015-12-02 22:53:26 +0100231#endif // if !defined(THREAD_SANITIZER) && !defined(WEBRTC_MAC)
wu@webrtc.org364f2042013-11-20 21:49:41 +0000232
buildbot@webrtc.orgda510c52014-05-13 22:30:56 +0000233// Disabled per b/14899892
234TEST_F(PeerConnectionEndToEndTest, DISABLED_CallWithLegacySdp) {
wu@webrtc.org364f2042013-11-20 21:49:41 +0000235 FakeConstraints pc_constraints;
236 pc_constraints.AddMandatory(MediaConstraintsInterface::kEnableDtlsSrtp,
237 false);
238 CreatePcs(&pc_constraints);
wu@webrtc.org364f2042013-11-20 21:49:41 +0000239 GetAndAddUserMedia();
240 Negotiate();
241 WaitForCallEstablished();
242}
wu@webrtc.orgb43202d2013-11-22 19:14:25 +0000243
jiayl@webrtc.org1a6c6282014-06-12 21:59:29 +0000244// Verifies that a DataChannel created before the negotiation can transition to
245// "OPEN" and transfer data.
246TEST_F(PeerConnectionEndToEndTest, CreateDataChannelBeforeNegotiate) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000247 MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp);
jiayl@webrtc.org1a6c6282014-06-12 21:59:29 +0000248
249 CreatePcs();
250
251 webrtc::DataChannelInit init;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000252 rtc::scoped_refptr<DataChannelInterface> caller_dc(
jiayl@webrtc.org1a6c6282014-06-12 21:59:29 +0000253 caller_->CreateDataChannel("data", init));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000254 rtc::scoped_refptr<DataChannelInterface> callee_dc(
jiayl@webrtc.org1a6c6282014-06-12 21:59:29 +0000255 callee_->CreateDataChannel("data", init));
256
257 Negotiate();
258 WaitForConnection();
259
260 WaitForDataChannelsToOpen(caller_dc, callee_signaled_data_channels_, 0);
261 WaitForDataChannelsToOpen(callee_dc, caller_signaled_data_channels_, 0);
262
263 TestDataChannelSendAndReceive(caller_dc, callee_signaled_data_channels_[0]);
264 TestDataChannelSendAndReceive(callee_dc, caller_signaled_data_channels_[0]);
265
266 CloseDataChannels(caller_dc, callee_signaled_data_channels_, 0);
267 CloseDataChannels(callee_dc, caller_signaled_data_channels_, 0);
268}
269
270// Verifies that a DataChannel created after the negotiation can transition to
271// "OPEN" and transfer data.
henrik.lundin@webrtc.org22362672014-11-03 13:38:50 +0000272#if defined(MEMORY_SANITIZER)
273// Fails under MemorySanitizer:
274// See https://code.google.com/p/webrtc/issues/detail?id=3980.
275#define MAYBE_CreateDataChannelAfterNegotiate DISABLED_CreateDataChannelAfterNegotiate
276#else
277#define MAYBE_CreateDataChannelAfterNegotiate CreateDataChannelAfterNegotiate
278#endif
279TEST_F(PeerConnectionEndToEndTest, MAYBE_CreateDataChannelAfterNegotiate) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000280 MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp);
jiayl@webrtc.org1a6c6282014-06-12 21:59:29 +0000281
282 CreatePcs();
283
284 webrtc::DataChannelInit init;
285
286 // This DataChannel is for creating the data content in the negotiation.
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000287 rtc::scoped_refptr<DataChannelInterface> dummy(
jiayl@webrtc.org1a6c6282014-06-12 21:59:29 +0000288 caller_->CreateDataChannel("data", init));
289 Negotiate();
290 WaitForConnection();
291
292 // Creates new DataChannels after the negotiation and verifies their states.
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000293 rtc::scoped_refptr<DataChannelInterface> caller_dc(
jiayl@webrtc.org1a6c6282014-06-12 21:59:29 +0000294 caller_->CreateDataChannel("hello", init));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000295 rtc::scoped_refptr<DataChannelInterface> callee_dc(
jiayl@webrtc.org1a6c6282014-06-12 21:59:29 +0000296 callee_->CreateDataChannel("hello", init));
297
298 WaitForDataChannelsToOpen(caller_dc, callee_signaled_data_channels_, 1);
299 WaitForDataChannelsToOpen(callee_dc, caller_signaled_data_channels_, 0);
300
301 TestDataChannelSendAndReceive(caller_dc, callee_signaled_data_channels_[1]);
302 TestDataChannelSendAndReceive(callee_dc, caller_signaled_data_channels_[0]);
303
304 CloseDataChannels(caller_dc, callee_signaled_data_channels_, 1);
305 CloseDataChannels(callee_dc, caller_signaled_data_channels_, 0);
306}
307
308// Verifies that DataChannel IDs are even/odd based on the DTLS roles.
309TEST_F(PeerConnectionEndToEndTest, DataChannelIdAssignment) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000310 MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp);
jiayl@webrtc.org1a6c6282014-06-12 21:59:29 +0000311
312 CreatePcs();
313
314 webrtc::DataChannelInit init;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000315 rtc::scoped_refptr<DataChannelInterface> caller_dc_1(
jiayl@webrtc.org1a6c6282014-06-12 21:59:29 +0000316 caller_->CreateDataChannel("data", init));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000317 rtc::scoped_refptr<DataChannelInterface> callee_dc_1(
jiayl@webrtc.org1a6c6282014-06-12 21:59:29 +0000318 callee_->CreateDataChannel("data", init));
319
320 Negotiate();
321 WaitForConnection();
322
323 EXPECT_EQ(1U, caller_dc_1->id() % 2);
324 EXPECT_EQ(0U, callee_dc_1->id() % 2);
325
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000326 rtc::scoped_refptr<DataChannelInterface> caller_dc_2(
jiayl@webrtc.org1a6c6282014-06-12 21:59:29 +0000327 caller_->CreateDataChannel("data", init));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000328 rtc::scoped_refptr<DataChannelInterface> callee_dc_2(
jiayl@webrtc.org1a6c6282014-06-12 21:59:29 +0000329 callee_->CreateDataChannel("data", init));
330
331 EXPECT_EQ(1U, caller_dc_2->id() % 2);
332 EXPECT_EQ(0U, callee_dc_2->id() % 2);
333}
334
335// Verifies that the message is received by the right remote DataChannel when
336// there are multiple DataChannels.
337TEST_F(PeerConnectionEndToEndTest,
338 MessageTransferBetweenTwoPairsOfDataChannels) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000339 MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp);
jiayl@webrtc.org1a6c6282014-06-12 21:59:29 +0000340
341 CreatePcs();
342
343 webrtc::DataChannelInit init;
344
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000345 rtc::scoped_refptr<DataChannelInterface> caller_dc_1(
jiayl@webrtc.org1a6c6282014-06-12 21:59:29 +0000346 caller_->CreateDataChannel("data", init));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000347 rtc::scoped_refptr<DataChannelInterface> caller_dc_2(
jiayl@webrtc.org1a6c6282014-06-12 21:59:29 +0000348 caller_->CreateDataChannel("data", init));
349
350 Negotiate();
351 WaitForConnection();
352 WaitForDataChannelsToOpen(caller_dc_1, callee_signaled_data_channels_, 0);
353 WaitForDataChannelsToOpen(caller_dc_2, callee_signaled_data_channels_, 1);
354
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000355 rtc::scoped_ptr<webrtc::MockDataChannelObserver> dc_1_observer(
jiayl@webrtc.org1a6c6282014-06-12 21:59:29 +0000356 new webrtc::MockDataChannelObserver(callee_signaled_data_channels_[0]));
357
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000358 rtc::scoped_ptr<webrtc::MockDataChannelObserver> dc_2_observer(
jiayl@webrtc.org1a6c6282014-06-12 21:59:29 +0000359 new webrtc::MockDataChannelObserver(callee_signaled_data_channels_[1]));
360
361 const std::string message_1 = "hello 1";
362 const std::string message_2 = "hello 2";
363
364 caller_dc_1->Send(webrtc::DataBuffer(message_1));
365 EXPECT_EQ_WAIT(message_1, dc_1_observer->last_message(), kMaxWait);
366
367 caller_dc_2->Send(webrtc::DataBuffer(message_2));
368 EXPECT_EQ_WAIT(message_2, dc_2_observer->last_message(), kMaxWait);
369
370 EXPECT_EQ(1U, dc_1_observer->received_message_count());
371 EXPECT_EQ(1U, dc_2_observer->received_message_count());
372}
deadbeefab9b2d12015-10-14 11:33:11 -0700373
374// Verifies that a DataChannel added from an OPEN message functions after
375// a channel has been previously closed (webrtc issue 3778).
376// This previously failed because the new channel re-uses the ID of the closed
377// channel, and the closed channel was incorrectly still assigned to the id.
378// TODO(deadbeef): This is disabled because there's currently a race condition
379// caused by the fact that a data channel signals that it's closed before it
380// really is. Re-enable this test once that's fixed.
381TEST_F(PeerConnectionEndToEndTest,
382 DISABLED_DataChannelFromOpenWorksAfterClose) {
383 MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp);
384
385 CreatePcs();
386
387 webrtc::DataChannelInit init;
388 rtc::scoped_refptr<DataChannelInterface> caller_dc(
389 caller_->CreateDataChannel("data", init));
390
391 Negotiate();
392 WaitForConnection();
393
394 WaitForDataChannelsToOpen(caller_dc, callee_signaled_data_channels_, 0);
395 CloseDataChannels(caller_dc, callee_signaled_data_channels_, 0);
396
397 // Create a new channel and ensure it works after closing the previous one.
398 caller_dc = caller_->CreateDataChannel("data2", init);
399
400 WaitForDataChannelsToOpen(caller_dc, callee_signaled_data_channels_, 1);
401 TestDataChannelSendAndReceive(caller_dc, callee_signaled_data_channels_[1]);
402
403 CloseDataChannels(caller_dc, callee_signaled_data_channels_, 1);
404}