Update talk to 56698267.
TBR=sergeyu@chromium.org Review URL: https://webrtc-codereview.appspot.com/4119004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@5143 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
dc50aaeaa8
commit
364f204d16
218
talk/app/webrtc/peerconnectionendtoend_unittest.cc
Normal file
218
talk/app/webrtc/peerconnectionendtoend_unittest.cc
Normal file
@ -0,0 +1,218 @@
|
||||
/*
|
||||
* libjingle
|
||||
* Copyright 2013, Google Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "talk/app/webrtc/test/peerconnectiontestwrapper.h"
|
||||
#include "talk/base/gunit.h"
|
||||
#include "talk/base/logging.h"
|
||||
#include "talk/base/ssladapter.h"
|
||||
#include "talk/base/sslstreamadapter.h"
|
||||
#include "talk/base/stringencode.h"
|
||||
#include "talk/base/stringutils.h"
|
||||
|
||||
using webrtc::FakeConstraints;
|
||||
using webrtc::MediaConstraintsInterface;
|
||||
using webrtc::MediaStreamInterface;
|
||||
using webrtc::PeerConnectionInterface;
|
||||
|
||||
namespace {
|
||||
|
||||
const char kExternalGiceUfrag[] = "1234567890123456";
|
||||
const char kExternalGicePwd[] = "123456789012345678901234";
|
||||
|
||||
void RemoveLinesFromSdp(const std::string& line_start,
|
||||
std::string* sdp) {
|
||||
const char kSdpLineEnd[] = "\r\n";
|
||||
size_t ssrc_pos = 0;
|
||||
while ((ssrc_pos = sdp->find(line_start, ssrc_pos)) !=
|
||||
std::string::npos) {
|
||||
size_t end_ssrc = sdp->find(kSdpLineEnd, ssrc_pos);
|
||||
sdp->erase(ssrc_pos, end_ssrc - ssrc_pos + strlen(kSdpLineEnd));
|
||||
}
|
||||
}
|
||||
|
||||
// Add |newlines| to the |message| after |line|.
|
||||
void InjectAfter(const std::string& line,
|
||||
const std::string& newlines,
|
||||
std::string* message) {
|
||||
const std::string tmp = line + newlines;
|
||||
talk_base::replace_substrs(line.c_str(), line.length(),
|
||||
tmp.c_str(), tmp.length(), message);
|
||||
}
|
||||
|
||||
void Replace(const std::string& line,
|
||||
const std::string& newlines,
|
||||
std::string* message) {
|
||||
talk_base::replace_substrs(line.c_str(), line.length(),
|
||||
newlines.c_str(), newlines.length(), message);
|
||||
}
|
||||
|
||||
void UseExternalSdes(std::string* sdp) {
|
||||
// Remove current crypto specification.
|
||||
RemoveLinesFromSdp("a=crypto", sdp);
|
||||
RemoveLinesFromSdp("a=fingerprint", sdp);
|
||||
// Add external crypto.
|
||||
const char kAudioSdes[] =
|
||||
"a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
|
||||
"inline:PS1uQCVeeCFCanVmcjkpPywjNWhcYD0mXXtxaVBR\r\n";
|
||||
const char kVideoSdes[] =
|
||||
"a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
|
||||
"inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj\r\n";
|
||||
const char kDataSdes[] =
|
||||
"a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
|
||||
"inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj\r\n";
|
||||
InjectAfter("a=mid:audio\r\n", kAudioSdes, sdp);
|
||||
InjectAfter("a=mid:video\r\n", kVideoSdes, sdp);
|
||||
InjectAfter("a=mid:data\r\n", kDataSdes, sdp);
|
||||
}
|
||||
|
||||
void UseGice(std::string* sdp) {
|
||||
InjectAfter("t=0 0\r\n", "a=ice-options:google-ice\r\n", sdp);
|
||||
|
||||
std::string ufragline = "a=ice-ufrag:";
|
||||
std::string pwdline = "a=ice-pwd:";
|
||||
RemoveLinesFromSdp(ufragline, sdp);
|
||||
RemoveLinesFromSdp(pwdline, sdp);
|
||||
ufragline.append(kExternalGiceUfrag);
|
||||
ufragline.append("\r\n");
|
||||
pwdline.append(kExternalGicePwd);
|
||||
pwdline.append("\r\n");
|
||||
const std::string ufrag_pwd = ufragline + pwdline;
|
||||
|
||||
InjectAfter("a=mid:audio\r\n", ufrag_pwd, sdp);
|
||||
InjectAfter("a=mid:video\r\n", ufrag_pwd, sdp);
|
||||
InjectAfter("a=mid:data\r\n", ufrag_pwd, sdp);
|
||||
}
|
||||
|
||||
void RemoveBundle(std::string* sdp) {
|
||||
RemoveLinesFromSdp("a=group:BUNDLE", sdp);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class PeerConnectionEndToEndTest
|
||||
: public sigslot::has_slots<>,
|
||||
public testing::Test {
|
||||
public:
|
||||
PeerConnectionEndToEndTest()
|
||||
: caller_(new talk_base::RefCountedObject<PeerConnectionTestWrapper>(
|
||||
"caller")),
|
||||
callee_(new talk_base::RefCountedObject<PeerConnectionTestWrapper>(
|
||||
"callee")) {
|
||||
talk_base::InitializeSSL(NULL);
|
||||
}
|
||||
|
||||
void CreatePcs() {
|
||||
CreatePcs(NULL);
|
||||
}
|
||||
|
||||
void CreatePcs(const MediaConstraintsInterface* pc_constraints) {
|
||||
EXPECT_TRUE(caller_->CreatePc(pc_constraints));
|
||||
EXPECT_TRUE(callee_->CreatePc(pc_constraints));
|
||||
PeerConnectionTestWrapper::Connect(caller_.get(), callee_.get());
|
||||
}
|
||||
|
||||
void GetAndAddUserMedia() {
|
||||
FakeConstraints audio_constraints;
|
||||
FakeConstraints video_constraints;
|
||||
GetAndAddUserMedia(true, audio_constraints, true, video_constraints);
|
||||
}
|
||||
|
||||
void GetAndAddUserMedia(bool audio, FakeConstraints audio_constraints,
|
||||
bool video, FakeConstraints video_constraints) {
|
||||
caller_->GetAndAddUserMedia(audio, audio_constraints,
|
||||
video, video_constraints);
|
||||
callee_->GetAndAddUserMedia(audio, audio_constraints,
|
||||
video, video_constraints);
|
||||
}
|
||||
|
||||
void Negotiate() {
|
||||
caller_->CreateOffer(NULL);
|
||||
}
|
||||
|
||||
void WaitForCallEstablished() {
|
||||
caller_->WaitForCallEstablished();
|
||||
callee_->WaitForCallEstablished();
|
||||
}
|
||||
|
||||
void SetupLegacySdpConverter() {
|
||||
caller_->SignalOnSdpCreated.connect(
|
||||
this, &PeerConnectionEndToEndTest::ConvertToLegacySdp);
|
||||
callee_->SignalOnSdpCreated.connect(
|
||||
this, &PeerConnectionEndToEndTest::ConvertToLegacySdp);
|
||||
}
|
||||
|
||||
void ConvertToLegacySdp(std::string* sdp) {
|
||||
UseExternalSdes(sdp);
|
||||
UseGice(sdp);
|
||||
RemoveBundle(sdp);
|
||||
LOG(LS_INFO) << "ConvertToLegacySdp: " << *sdp;
|
||||
}
|
||||
|
||||
void SetupGiceConverter() {
|
||||
caller_->SignalOnIceCandidateCreated.connect(
|
||||
this, &PeerConnectionEndToEndTest::AddGiceCredsToCandidate);
|
||||
callee_->SignalOnIceCandidateCreated.connect(
|
||||
this, &PeerConnectionEndToEndTest::AddGiceCredsToCandidate);
|
||||
}
|
||||
|
||||
void AddGiceCredsToCandidate(std::string* sdp) {
|
||||
std::string gice_creds = " username ";
|
||||
gice_creds.append(kExternalGiceUfrag);
|
||||
gice_creds.append(" password ");
|
||||
gice_creds.append(kExternalGicePwd);
|
||||
gice_creds.append("\r\n");
|
||||
Replace("\r\n", gice_creds, sdp);
|
||||
LOG(LS_INFO) << "AddGiceCredsToCandidate: " << *sdp;
|
||||
}
|
||||
|
||||
~PeerConnectionEndToEndTest() {
|
||||
talk_base::CleanupSSL();
|
||||
}
|
||||
|
||||
protected:
|
||||
talk_base::scoped_refptr<PeerConnectionTestWrapper> caller_;
|
||||
talk_base::scoped_refptr<PeerConnectionTestWrapper> callee_;
|
||||
};
|
||||
|
||||
TEST_F(PeerConnectionEndToEndTest, Call) {
|
||||
CreatePcs();
|
||||
GetAndAddUserMedia();
|
||||
Negotiate();
|
||||
WaitForCallEstablished();
|
||||
}
|
||||
|
||||
TEST_F(PeerConnectionEndToEndTest, CallWithLegacySdp) {
|
||||
FakeConstraints pc_constraints;
|
||||
pc_constraints.AddMandatory(MediaConstraintsInterface::kEnableDtlsSrtp,
|
||||
false);
|
||||
CreatePcs(&pc_constraints);
|
||||
SetupLegacySdpConverter();
|
||||
SetupGiceConverter();
|
||||
GetAndAddUserMedia();
|
||||
Negotiate();
|
||||
WaitForCallEstablished();
|
||||
}
|
@ -100,6 +100,8 @@ const char StatsReport::kStatsValueNameInitiator[] = "googInitiator";
|
||||
const char StatsReport::kStatsValueNameIssuerId[] = "googIssuerId";
|
||||
const char StatsReport::kStatsValueNameJitterReceived[] = "googJitterReceived";
|
||||
const char StatsReport::kStatsValueNameLocalAddress[] = "googLocalAddress";
|
||||
const char StatsReport::kStatsValueNameLocalCandidateType[] =
|
||||
"googLocalCandidateType";
|
||||
const char StatsReport::kStatsValueNameLocalCertificateId[] =
|
||||
"googLocalCertificateId";
|
||||
const char StatsReport::kStatsValueNameNacksReceived[] = "googNacksReceived";
|
||||
@ -109,6 +111,8 @@ const char StatsReport::kStatsValueNamePacketsSent[] = "packetsSent";
|
||||
const char StatsReport::kStatsValueNamePacketsLost[] = "packetsLost";
|
||||
const char StatsReport::kStatsValueNameReadable[] = "googReadable";
|
||||
const char StatsReport::kStatsValueNameRemoteAddress[] = "googRemoteAddress";
|
||||
const char StatsReport::kStatsValueNameRemoteCandidateType[] =
|
||||
"googRemoteCandidateType";
|
||||
const char StatsReport::kStatsValueNameRemoteCertificateId[] =
|
||||
"googRemoteCertificateId";
|
||||
const char StatsReport::kStatsValueNameRetransmitBitrate[] =
|
||||
@ -678,6 +682,10 @@ void StatsCollector::ExtractSessionInfo() {
|
||||
report.AddValue(StatsReport::kStatsValueNameRtt, info.rtt);
|
||||
report.AddValue(StatsReport::kStatsValueNameTransportType,
|
||||
info.local_candidate.protocol());
|
||||
report.AddValue(StatsReport::kStatsValueNameLocalCandidateType,
|
||||
info.local_candidate.type());
|
||||
report.AddValue(StatsReport::kStatsValueNameRemoteCandidateType,
|
||||
info.remote_candidate.type());
|
||||
reports_[report.id] = report;
|
||||
}
|
||||
}
|
||||
|
@ -177,6 +177,8 @@ class StatsReport {
|
||||
static const char kStatsValueNameIssuerId[];
|
||||
static const char kStatsValueNameLocalCertificateId[];
|
||||
static const char kStatsValueNameRemoteCertificateId[];
|
||||
static const char kStatsValueNameLocalCandidateType[];
|
||||
static const char kStatsValueNameRemoteCandidateType[];
|
||||
};
|
||||
|
||||
typedef std::vector<StatsReport> StatsReports;
|
||||
|
278
talk/app/webrtc/test/peerconnectiontestwrapper.cc
Normal file
278
talk/app/webrtc/test/peerconnectiontestwrapper.cc
Normal file
@ -0,0 +1,278 @@
|
||||
/*
|
||||
* libjingle
|
||||
* Copyright 2013, Google Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "talk/app/webrtc/fakeportallocatorfactory.h"
|
||||
#include "talk/app/webrtc/test/fakeperiodicvideocapturer.h"
|
||||
#include "talk/app/webrtc/test/mockpeerconnectionobservers.h"
|
||||
#include "talk/app/webrtc/test/peerconnectiontestwrapper.h"
|
||||
#include "talk/app/webrtc/videosourceinterface.h"
|
||||
#include "talk/base/gunit.h"
|
||||
|
||||
static const char kStreamLabelBase[] = "stream_label";
|
||||
static const char kVideoTrackLabelBase[] = "video_track";
|
||||
static const char kAudioTrackLabelBase[] = "audio_track";
|
||||
static const int kMaxWait = 5000;
|
||||
static const int kTestAudioFrameCount = 3;
|
||||
static const int kTestVideoFrameCount = 3;
|
||||
|
||||
using webrtc::FakeConstraints;
|
||||
using webrtc::FakeVideoTrackRenderer;
|
||||
using webrtc::IceCandidateInterface;
|
||||
using webrtc::MediaConstraintsInterface;
|
||||
using webrtc::MediaStreamInterface;
|
||||
using webrtc::MockSetSessionDescriptionObserver;
|
||||
using webrtc::PeerConnectionInterface;
|
||||
using webrtc::SessionDescriptionInterface;
|
||||
using webrtc::VideoTrackInterface;
|
||||
|
||||
void PeerConnectionTestWrapper::Connect(PeerConnectionTestWrapper* caller,
|
||||
PeerConnectionTestWrapper* callee) {
|
||||
caller->SignalOnIceCandidateReady.connect(
|
||||
callee, &PeerConnectionTestWrapper::AddIceCandidate);
|
||||
callee->SignalOnIceCandidateReady.connect(
|
||||
caller, &PeerConnectionTestWrapper::AddIceCandidate);
|
||||
|
||||
caller->SignalOnSdpReady.connect(
|
||||
callee, &PeerConnectionTestWrapper::ReceiveOfferSdp);
|
||||
callee->SignalOnSdpReady.connect(
|
||||
caller, &PeerConnectionTestWrapper::ReceiveAnswerSdp);
|
||||
}
|
||||
|
||||
PeerConnectionTestWrapper::PeerConnectionTestWrapper(const std::string& name)
|
||||
: name_(name) {}
|
||||
|
||||
PeerConnectionTestWrapper::~PeerConnectionTestWrapper() {}
|
||||
|
||||
bool PeerConnectionTestWrapper::CreatePc(
|
||||
const MediaConstraintsInterface* constraints) {
|
||||
allocator_factory_ = webrtc::FakePortAllocatorFactory::Create();
|
||||
if (!allocator_factory_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
audio_thread_.Start();
|
||||
fake_audio_capture_module_ = FakeAudioCaptureModule::Create(
|
||||
&audio_thread_);
|
||||
if (fake_audio_capture_module_ == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
peer_connection_factory_ = webrtc::CreatePeerConnectionFactory(
|
||||
talk_base::Thread::Current(), talk_base::Thread::Current(),
|
||||
fake_audio_capture_module_, NULL, NULL);
|
||||
if (!peer_connection_factory_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// CreatePeerConnection with IceServers.
|
||||
webrtc::PeerConnectionInterface::IceServers ice_servers;
|
||||
webrtc::PeerConnectionInterface::IceServer ice_server;
|
||||
ice_server.uri = "stun:stun.l.google.com:19302";
|
||||
ice_servers.push_back(ice_server);
|
||||
peer_connection_ = peer_connection_factory_->CreatePeerConnection(
|
||||
ice_servers, constraints, allocator_factory_.get(), NULL, this);
|
||||
|
||||
return peer_connection_.get() != NULL;
|
||||
}
|
||||
|
||||
void PeerConnectionTestWrapper::OnAddStream(MediaStreamInterface* stream) {
|
||||
LOG(LS_INFO) << "PeerConnectionTestWrapper " << name_
|
||||
<< ": OnAddStream";
|
||||
// TODO(ronghuawu): support multiple streams.
|
||||
if (stream->GetVideoTracks().size() > 0) {
|
||||
renderer_.reset(new FakeVideoTrackRenderer(stream->GetVideoTracks()[0]));
|
||||
}
|
||||
}
|
||||
|
||||
void PeerConnectionTestWrapper::OnIceCandidate(
|
||||
const IceCandidateInterface* candidate) {
|
||||
std::string sdp;
|
||||
EXPECT_TRUE(candidate->ToString(&sdp));
|
||||
// Give the user a chance to modify sdp for testing.
|
||||
SignalOnIceCandidateCreated(&sdp);
|
||||
SignalOnIceCandidateReady(candidate->sdp_mid(), candidate->sdp_mline_index(),
|
||||
sdp);
|
||||
}
|
||||
|
||||
void PeerConnectionTestWrapper::OnSuccess(SessionDescriptionInterface* desc) {
|
||||
std::string sdp;
|
||||
EXPECT_TRUE(desc->ToString(&sdp));
|
||||
|
||||
LOG(LS_INFO) << "PeerConnectionTestWrapper " << name_
|
||||
<< ": " << desc->type() << " sdp created: " << sdp;
|
||||
|
||||
// Give the user a chance to modify sdp for testing.
|
||||
SignalOnSdpCreated(&sdp);
|
||||
|
||||
SetLocalDescription(desc->type(), sdp);
|
||||
|
||||
SignalOnSdpReady(sdp);
|
||||
}
|
||||
|
||||
void PeerConnectionTestWrapper::CreateOffer(
|
||||
const MediaConstraintsInterface* constraints) {
|
||||
LOG(LS_INFO) << "PeerConnectionTestWrapper " << name_
|
||||
<< ": CreateOffer.";
|
||||
peer_connection_->CreateOffer(this, constraints);
|
||||
}
|
||||
|
||||
void PeerConnectionTestWrapper::CreateAnswer(
|
||||
const MediaConstraintsInterface* constraints) {
|
||||
LOG(LS_INFO) << "PeerConnectionTestWrapper " << name_
|
||||
<< ": CreateAnswer.";
|
||||
peer_connection_->CreateAnswer(this, constraints);
|
||||
}
|
||||
|
||||
void PeerConnectionTestWrapper::ReceiveOfferSdp(const std::string& sdp) {
|
||||
SetRemoteDescription(SessionDescriptionInterface::kOffer, sdp);
|
||||
CreateAnswer(NULL);
|
||||
}
|
||||
|
||||
void PeerConnectionTestWrapper::ReceiveAnswerSdp(const std::string& sdp) {
|
||||
SetRemoteDescription(SessionDescriptionInterface::kAnswer, sdp);
|
||||
}
|
||||
|
||||
void PeerConnectionTestWrapper::SetLocalDescription(const std::string& type,
|
||||
const std::string& sdp) {
|
||||
LOG(LS_INFO) << "PeerConnectionTestWrapper " << name_
|
||||
<< ": SetLocalDescription " << type << " " << sdp;
|
||||
|
||||
talk_base::scoped_refptr<MockSetSessionDescriptionObserver>
|
||||
observer(new talk_base::RefCountedObject<
|
||||
MockSetSessionDescriptionObserver>());
|
||||
peer_connection_->SetLocalDescription(
|
||||
observer, webrtc::CreateSessionDescription(type, sdp, NULL));
|
||||
}
|
||||
|
||||
void PeerConnectionTestWrapper::SetRemoteDescription(const std::string& type,
|
||||
const std::string& sdp) {
|
||||
LOG(LS_INFO) << "PeerConnectionTestWrapper " << name_
|
||||
<< ": SetRemoteDescription " << type << " " << sdp;
|
||||
|
||||
talk_base::scoped_refptr<MockSetSessionDescriptionObserver>
|
||||
observer(new talk_base::RefCountedObject<
|
||||
MockSetSessionDescriptionObserver>());
|
||||
peer_connection_->SetRemoteDescription(
|
||||
observer, webrtc::CreateSessionDescription(type, sdp, NULL));
|
||||
}
|
||||
|
||||
void PeerConnectionTestWrapper::AddIceCandidate(const std::string& sdp_mid,
|
||||
int sdp_mline_index,
|
||||
const std::string& candidate) {
|
||||
EXPECT_TRUE(peer_connection_->AddIceCandidate(
|
||||
webrtc::CreateIceCandidate(sdp_mid, sdp_mline_index,
|
||||
candidate, NULL)));
|
||||
}
|
||||
|
||||
void PeerConnectionTestWrapper::WaitForCallEstablished() {
|
||||
WaitForConnection();
|
||||
WaitForAudio();
|
||||
WaitForVideo();
|
||||
}
|
||||
|
||||
void PeerConnectionTestWrapper::WaitForConnection() {
|
||||
EXPECT_TRUE_WAIT(CheckForConnection(), kMaxWait);
|
||||
LOG(LS_INFO) << "PeerConnectionTestWrapper " << name_
|
||||
<< ": Connected.";
|
||||
}
|
||||
|
||||
bool PeerConnectionTestWrapper::CheckForConnection() {
|
||||
return (peer_connection_->ice_connection_state() ==
|
||||
PeerConnectionInterface::kIceConnectionConnected);
|
||||
}
|
||||
|
||||
void PeerConnectionTestWrapper::WaitForAudio() {
|
||||
EXPECT_TRUE_WAIT(CheckForAudio(), kMaxWait);
|
||||
LOG(LS_INFO) << "PeerConnectionTestWrapper " << name_
|
||||
<< ": Got enough audio frames.";
|
||||
}
|
||||
|
||||
bool PeerConnectionTestWrapper::CheckForAudio() {
|
||||
return (fake_audio_capture_module_->frames_received() >=
|
||||
kTestAudioFrameCount);
|
||||
}
|
||||
|
||||
void PeerConnectionTestWrapper::WaitForVideo() {
|
||||
EXPECT_TRUE_WAIT(CheckForVideo(), kMaxWait);
|
||||
LOG(LS_INFO) << "PeerConnectionTestWrapper " << name_
|
||||
<< ": Got enough video frames.";
|
||||
}
|
||||
|
||||
bool PeerConnectionTestWrapper::CheckForVideo() {
|
||||
if (!renderer_) {
|
||||
return false;
|
||||
}
|
||||
return (renderer_->num_rendered_frames() >= kTestVideoFrameCount);
|
||||
}
|
||||
|
||||
void PeerConnectionTestWrapper::GetAndAddUserMedia(
|
||||
bool audio, const webrtc::FakeConstraints& audio_constraints,
|
||||
bool video, const webrtc::FakeConstraints& video_constraints) {
|
||||
talk_base::scoped_refptr<webrtc::MediaStreamInterface> stream =
|
||||
GetUserMedia(audio, audio_constraints, video, video_constraints);
|
||||
EXPECT_TRUE(peer_connection_->AddStream(stream, NULL));
|
||||
}
|
||||
|
||||
talk_base::scoped_refptr<webrtc::MediaStreamInterface>
|
||||
PeerConnectionTestWrapper::GetUserMedia(
|
||||
bool audio, const webrtc::FakeConstraints& audio_constraints,
|
||||
bool video, const webrtc::FakeConstraints& video_constraints) {
|
||||
std::string label = kStreamLabelBase +
|
||||
talk_base::ToString<int>(
|
||||
static_cast<int>(peer_connection_->local_streams()->count()));
|
||||
talk_base::scoped_refptr<webrtc::MediaStreamInterface> stream =
|
||||
peer_connection_factory_->CreateLocalMediaStream(label);
|
||||
|
||||
if (audio) {
|
||||
FakeConstraints constraints = audio_constraints;
|
||||
// Disable highpass filter so that we can get all the test audio frames.
|
||||
constraints.AddMandatory(
|
||||
MediaConstraintsInterface::kHighpassFilter, false);
|
||||
talk_base::scoped_refptr<webrtc::AudioSourceInterface> source =
|
||||
peer_connection_factory_->CreateAudioSource(&constraints);
|
||||
talk_base::scoped_refptr<webrtc::AudioTrackInterface> audio_track(
|
||||
peer_connection_factory_->CreateAudioTrack(kAudioTrackLabelBase,
|
||||
source));
|
||||
stream->AddTrack(audio_track);
|
||||
}
|
||||
|
||||
if (video) {
|
||||
// Set max frame rate to 10fps to reduce the risk of the tests to be flaky.
|
||||
FakeConstraints constraints = video_constraints;
|
||||
constraints.SetMandatoryMaxFrameRate(10);
|
||||
|
||||
talk_base::scoped_refptr<webrtc::VideoSourceInterface> source =
|
||||
peer_connection_factory_->CreateVideoSource(
|
||||
new webrtc::FakePeriodicVideoCapturer(), &constraints);
|
||||
std::string videotrack_label = label + kVideoTrackLabelBase;
|
||||
talk_base::scoped_refptr<webrtc::VideoTrackInterface> video_track(
|
||||
peer_connection_factory_->CreateVideoTrack(videotrack_label, source));
|
||||
|
||||
stream->AddTrack(video_track);
|
||||
}
|
||||
return stream;
|
||||
}
|
119
talk/app/webrtc/test/peerconnectiontestwrapper.h
Normal file
119
talk/app/webrtc/test/peerconnectiontestwrapper.h
Normal file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* libjingle
|
||||
* Copyright 2013, Google Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef TALK_APP_WEBRTC_TEST_PEERCONNECTIONTESTWRAPPER_H_
|
||||
#define TALK_APP_WEBRTC_TEST_PEERCONNECTIONTESTWRAPPER_H_
|
||||
|
||||
#include "talk/app/webrtc/peerconnectioninterface.h"
|
||||
#include "talk/app/webrtc/test/fakeaudiocapturemodule.h"
|
||||
#include "talk/app/webrtc/test/fakeconstraints.h"
|
||||
#include "talk/app/webrtc/test/fakevideotrackrenderer.h"
|
||||
#include "talk/base/sigslot.h"
|
||||
#include "talk/base/thread.h"
|
||||
|
||||
namespace webrtc {
|
||||
class PortAllocatorFactoryInterface;
|
||||
}
|
||||
|
||||
class PeerConnectionTestWrapper
|
||||
: public webrtc::PeerConnectionObserver,
|
||||
public webrtc::CreateSessionDescriptionObserver,
|
||||
public sigslot::has_slots<> {
|
||||
public:
|
||||
static void Connect(PeerConnectionTestWrapper* caller,
|
||||
PeerConnectionTestWrapper* callee);
|
||||
|
||||
explicit PeerConnectionTestWrapper(const std::string& name);
|
||||
virtual ~PeerConnectionTestWrapper();
|
||||
|
||||
bool CreatePc(const webrtc::MediaConstraintsInterface* constraints);
|
||||
|
||||
// Implements PeerConnectionObserver.
|
||||
virtual void OnError() {}
|
||||
virtual void OnSignalingChange(
|
||||
webrtc::PeerConnectionInterface::SignalingState new_state) {}
|
||||
virtual void OnStateChange(
|
||||
webrtc::PeerConnectionObserver::StateType state_changed) {}
|
||||
virtual void OnAddStream(webrtc::MediaStreamInterface* stream);
|
||||
virtual void OnRemoveStream(webrtc::MediaStreamInterface* stream) {}
|
||||
virtual void OnDataChannel(webrtc::DataChannelInterface* data_channel) {}
|
||||
virtual void OnRenegotiationNeeded() {}
|
||||
virtual void OnIceConnectionChange(
|
||||
webrtc::PeerConnectionInterface::IceConnectionState new_state) {}
|
||||
virtual void OnIceGatheringChange(
|
||||
webrtc::PeerConnectionInterface::IceGatheringState new_state) {}
|
||||
virtual void OnIceCandidate(const webrtc::IceCandidateInterface* candidate);
|
||||
virtual void OnIceComplete() {}
|
||||
|
||||
// Implements CreateSessionDescriptionObserver.
|
||||
virtual void OnSuccess(webrtc::SessionDescriptionInterface* desc);
|
||||
virtual void OnFailure(const std::string& error) {}
|
||||
|
||||
void CreateOffer(const webrtc::MediaConstraintsInterface* constraints);
|
||||
void CreateAnswer(const webrtc::MediaConstraintsInterface* constraints);
|
||||
void ReceiveOfferSdp(const std::string& sdp);
|
||||
void ReceiveAnswerSdp(const std::string& sdp);
|
||||
void AddIceCandidate(const std::string& sdp_mid, int sdp_mline_index,
|
||||
const std::string& candidate);
|
||||
void WaitForCallEstablished();
|
||||
void WaitForConnection();
|
||||
void WaitForAudio();
|
||||
void WaitForVideo();
|
||||
void GetAndAddUserMedia(
|
||||
bool audio, const webrtc::FakeConstraints& audio_constraints,
|
||||
bool video, const webrtc::FakeConstraints& video_constraints);
|
||||
|
||||
// sigslots
|
||||
sigslot::signal1<std::string*> SignalOnIceCandidateCreated;
|
||||
sigslot::signal3<const std::string&,
|
||||
int,
|
||||
const std::string&> SignalOnIceCandidateReady;
|
||||
sigslot::signal1<std::string*> SignalOnSdpCreated;
|
||||
sigslot::signal1<const std::string&> SignalOnSdpReady;
|
||||
|
||||
private:
|
||||
void SetLocalDescription(const std::string& type, const std::string& sdp);
|
||||
void SetRemoteDescription(const std::string& type, const std::string& sdp);
|
||||
bool CheckForConnection();
|
||||
bool CheckForAudio();
|
||||
bool CheckForVideo();
|
||||
talk_base::scoped_refptr<webrtc::MediaStreamInterface> GetUserMedia(
|
||||
bool audio, const webrtc::FakeConstraints& audio_constraints,
|
||||
bool video, const webrtc::FakeConstraints& video_constraints);
|
||||
|
||||
std::string name_;
|
||||
talk_base::Thread audio_thread_;
|
||||
talk_base::scoped_refptr<webrtc::PortAllocatorFactoryInterface>
|
||||
allocator_factory_;
|
||||
talk_base::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection_;
|
||||
talk_base::scoped_refptr<webrtc::PeerConnectionFactoryInterface>
|
||||
peer_connection_factory_;
|
||||
talk_base::scoped_refptr<FakeAudioCaptureModule> fake_audio_capture_module_;
|
||||
talk_base::scoped_ptr<webrtc::FakeVideoTrackRenderer> renderer_;
|
||||
};
|
||||
|
||||
#endif // TALK_APP_WEBRTC_TEST_PEERCONNECTIONTESTWRAPPER_H_
|
@ -526,7 +526,7 @@ bool WebRtcSession::Initialize(
|
||||
this, &WebRtcSession::OnIdentityReady);
|
||||
|
||||
if (options.disable_encryption) {
|
||||
webrtc_session_desc_factory_->set_secure(cricket::SEC_DISABLED);
|
||||
webrtc_session_desc_factory_->SetSecure(cricket::SEC_DISABLED);
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -554,13 +554,13 @@ bool WebRtcSession::StartCandidatesAllocation() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void WebRtcSession::set_secure_policy(
|
||||
void WebRtcSession::SetSecurePolicy(
|
||||
cricket::SecureMediaPolicy secure_policy) {
|
||||
webrtc_session_desc_factory_->set_secure(secure_policy);
|
||||
webrtc_session_desc_factory_->SetSecure(secure_policy);
|
||||
}
|
||||
|
||||
cricket::SecureMediaPolicy WebRtcSession::secure_policy() const {
|
||||
return webrtc_session_desc_factory_->secure();
|
||||
cricket::SecureMediaPolicy WebRtcSession::SecurePolicy() const {
|
||||
return webrtc_session_desc_factory_->Secure();
|
||||
}
|
||||
|
||||
bool WebRtcSession::GetSslRole(talk_base::SSLRole* role) {
|
||||
@ -610,7 +610,7 @@ bool WebRtcSession::SetLocalDescription(SessionDescriptionInterface* desc,
|
||||
}
|
||||
|
||||
cricket::SecureMediaPolicy secure_policy =
|
||||
webrtc_session_desc_factory_->secure();
|
||||
webrtc_session_desc_factory_->Secure();
|
||||
// Update the MediaContentDescription crypto settings as per the policy set.
|
||||
UpdateSessionDescriptionSecurePolicy(secure_policy, desc->description());
|
||||
|
||||
@ -1483,7 +1483,7 @@ bool WebRtcSession::ValidateSessionDescription(
|
||||
|
||||
// Verify crypto settings.
|
||||
std::string crypto_error;
|
||||
if (webrtc_session_desc_factory_->secure() == cricket::SEC_REQUIRED &&
|
||||
if (webrtc_session_desc_factory_->Secure() == cricket::SEC_REQUIRED &&
|
||||
!VerifyCrypto(sdesc->description(), dtls_enabled_, &crypto_error)) {
|
||||
return BadSdp(source, crypto_error, error_desc);
|
||||
}
|
||||
|
@ -42,20 +42,17 @@
|
||||
#include "talk/session/media/mediasession.h"
|
||||
|
||||
namespace cricket {
|
||||
|
||||
class BaseChannel;
|
||||
class ChannelManager;
|
||||
class DataChannel;
|
||||
class StatsReport;
|
||||
class Transport;
|
||||
class VideoCapturer;
|
||||
class BaseChannel;
|
||||
class VideoChannel;
|
||||
class VoiceChannel;
|
||||
|
||||
} // namespace cricket
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class IceRestartAnswerLatch;
|
||||
class MediaStreamSignaling;
|
||||
class WebRtcSessionDescriptionFactory;
|
||||
@ -79,6 +76,7 @@ extern const char kPushDownAnswerTDFailed[];
|
||||
// ICE state callback interface.
|
||||
class IceObserver {
|
||||
public:
|
||||
IceObserver() {}
|
||||
// Called any time the IceConnectionState changes
|
||||
virtual void OnIceConnectionChange(
|
||||
PeerConnectionInterface::IceConnectionState new_state) {}
|
||||
@ -94,6 +92,9 @@ class IceObserver {
|
||||
|
||||
protected:
|
||||
~IceObserver() {}
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(IceObserver);
|
||||
};
|
||||
|
||||
class WebRtcSession : public cricket::BaseSession,
|
||||
@ -131,8 +132,8 @@ class WebRtcSession : public cricket::BaseSession,
|
||||
return data_channel_.get();
|
||||
}
|
||||
|
||||
void set_secure_policy(cricket::SecureMediaPolicy secure_policy);
|
||||
cricket::SecureMediaPolicy secure_policy() const;
|
||||
void SetSecurePolicy(cricket::SecureMediaPolicy secure_policy);
|
||||
cricket::SecureMediaPolicy SecurePolicy() const;
|
||||
|
||||
// Get current ssl role from transport.
|
||||
bool GetSslRole(talk_base::SSLRole* role);
|
||||
@ -330,8 +331,9 @@ class WebRtcSession : public cricket::BaseSession,
|
||||
sigslot::signal0<> SignalVoiceChannelDestroyed;
|
||||
sigslot::signal0<> SignalVideoChannelDestroyed;
|
||||
sigslot::signal0<> SignalDataChannelDestroyed;
|
||||
};
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(WebRtcSession);
|
||||
};
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // TALK_APP_WEBRTC_WEBRTCSESSION_H_
|
||||
|
@ -86,20 +86,21 @@ using webrtc::PeerConnectionInterface;
|
||||
using webrtc::SessionDescriptionInterface;
|
||||
using webrtc::StreamCollection;
|
||||
using webrtc::WebRtcSession;
|
||||
using webrtc::kBundleWithoutRtcpMux;
|
||||
using webrtc::kMlineMismatch;
|
||||
using webrtc::kPushDownAnswerTDFailed;
|
||||
using webrtc::kPushDownPranswerTDFailed;
|
||||
using webrtc::kSdpWithoutCrypto;
|
||||
using webrtc::kSdpWithoutSdesAndDtlsDisabled;
|
||||
using webrtc::kSdpWithoutIceUfragPwd;
|
||||
using webrtc::kSdpWithoutSdesAndDtlsDisabled;
|
||||
using webrtc::kSessionError;
|
||||
using webrtc::kSetLocalSdpFailed;
|
||||
using webrtc::kSetRemoteSdpFailed;
|
||||
using webrtc::kPushDownAnswerTDFailed;
|
||||
using webrtc::kPushDownPranswerTDFailed;
|
||||
using webrtc::kBundleWithoutRtcpMux;
|
||||
|
||||
static const SocketAddress kClientAddr1("11.11.11.11", 0);
|
||||
static const SocketAddress kClientAddr2("22.22.22.22", 0);
|
||||
static const SocketAddress kStunAddr("99.99.99.1", cricket::STUN_SERVER_PORT);
|
||||
static const int kClientAddrPort = 0;
|
||||
static const char kClientAddrHost1[] = "11.11.11.11";
|
||||
static const char kClientAddrHost2[] = "22.22.22.22";
|
||||
static const char kStunAddrHost[] = "99.99.99.1";
|
||||
|
||||
static const char kSessionVersion[] = "1";
|
||||
|
||||
@ -113,11 +114,6 @@ static const char kMediaContentName1[] = "video";
|
||||
|
||||
static const int kIceCandidatesTimeout = 10000;
|
||||
|
||||
static const cricket::AudioCodec
|
||||
kTelephoneEventCodec(106, "telephone-event", 8000, 0, 1, 0);
|
||||
static const cricket::AudioCodec kCNCodec1(102, "CN", 8000, 0, 1, 0);
|
||||
static const cricket::AudioCodec kCNCodec2(103, "CN", 16000, 0, 1, 0);
|
||||
|
||||
static const char kFakeDtlsFingerprint[] =
|
||||
"BB:CD:72:F7:2F:D0:BA:43:F3:68:B1:0C:23:72:B6:4A:"
|
||||
"0F:DE:34:06:BC:E0:FE:01:BC:73:C8:6D:F4:65:D5:24";
|
||||
@ -159,11 +155,17 @@ class MockIceObserver : public webrtc::IceObserver {
|
||||
|
||||
// Found a new candidate.
|
||||
virtual void OnIceCandidate(const webrtc::IceCandidateInterface* candidate) {
|
||||
if (candidate->sdp_mline_index() == kMediaContentIndex0) {
|
||||
mline_0_candidates_.push_back(candidate->candidate());
|
||||
} else if (candidate->sdp_mline_index() == kMediaContentIndex1) {
|
||||
mline_1_candidates_.push_back(candidate->candidate());
|
||||
switch (candidate->sdp_mline_index()) {
|
||||
case kMediaContentIndex0:
|
||||
mline_0_candidates_.push_back(candidate->candidate());
|
||||
break;
|
||||
case kMediaContentIndex1:
|
||||
mline_1_candidates_.push_back(candidate->candidate());
|
||||
break;
|
||||
default:
|
||||
ASSERT(false);
|
||||
}
|
||||
|
||||
// The ICE gathering state should always be Gathering when a candidate is
|
||||
// received (or possibly Completed in the case of the final candidate).
|
||||
EXPECT_NE(PeerConnectionInterface::kIceGatheringNew, ice_gathering_state_);
|
||||
@ -281,8 +283,10 @@ class WebRtcSessionTest : public testing::Test {
|
||||
vss_(new talk_base::VirtualSocketServer(pss_.get())),
|
||||
fss_(new talk_base::FirewallSocketServer(vss_.get())),
|
||||
ss_scope_(fss_.get()),
|
||||
stun_server_(talk_base::Thread::Current(), kStunAddr),
|
||||
allocator_(&network_manager_, kStunAddr,
|
||||
stun_socket_addr_(talk_base::SocketAddress(kStunAddrHost,
|
||||
cricket::STUN_SERVER_PORT)),
|
||||
stun_server_(talk_base::Thread::Current(), stun_socket_addr_),
|
||||
allocator_(&network_manager_, stun_socket_addr_,
|
||||
SocketAddress(), SocketAddress(), SocketAddress()),
|
||||
mediastream_signaling_(channel_manager_.get()) {
|
||||
tdesc_factory_->set_protocol(cricket::ICEPROTO_HYBRID);
|
||||
@ -324,6 +328,8 @@ class WebRtcSessionTest : public testing::Test {
|
||||
|
||||
void InitWithDtmfCodec() {
|
||||
// Add kTelephoneEventCodec for dtmf test.
|
||||
const cricket::AudioCodec kTelephoneEventCodec(
|
||||
106, "telephone-event", 8000, 0, 1, 0);
|
||||
std::vector<cricket::AudioCodec> codecs;
|
||||
codecs.push_back(kTelephoneEventCodec);
|
||||
media_engine_->SetAudioCodecs(codecs);
|
||||
@ -370,12 +376,12 @@ class WebRtcSessionTest : public testing::Test {
|
||||
return observer->ReleaseDescription();
|
||||
}
|
||||
|
||||
bool ChannelsExist() {
|
||||
bool ChannelsExist() const {
|
||||
return (session_->voice_channel() != NULL &&
|
||||
session_->video_channel() != NULL);
|
||||
}
|
||||
|
||||
void CheckTransportChannels() {
|
||||
void CheckTransportChannels() const {
|
||||
EXPECT_TRUE(session_->GetChannel(cricket::CN_AUDIO, 1) != NULL);
|
||||
EXPECT_TRUE(session_->GetChannel(cricket::CN_AUDIO, 2) != NULL);
|
||||
EXPECT_TRUE(session_->GetChannel(cricket::CN_VIDEO, 1) != NULL);
|
||||
@ -710,7 +716,7 @@ class WebRtcSessionTest : public testing::Test {
|
||||
}
|
||||
|
||||
void TestSessionCandidatesWithBundleRtcpMux(bool bundle, bool rtcp_mux) {
|
||||
AddInterface(kClientAddr1);
|
||||
AddInterface(talk_base::SocketAddress(kClientAddrHost1, kClientAddrPort));
|
||||
Init(NULL);
|
||||
mediastream_signaling_.SendAudioVideoStream1();
|
||||
FakeConstraints constraints;
|
||||
@ -780,7 +786,7 @@ class WebRtcSessionTest : public testing::Test {
|
||||
// New -> Checking -> Connected -> Disconnected -> Connected.
|
||||
// The Gathering state should go: New -> Gathering -> Completed.
|
||||
void TestLoopbackCall() {
|
||||
AddInterface(kClientAddr1);
|
||||
AddInterface(talk_base::SocketAddress(kClientAddrHost1, kClientAddrPort));
|
||||
Init(NULL);
|
||||
mediastream_signaling_.SendAudioVideoStream1();
|
||||
SessionDescriptionInterface* offer = CreateOffer(NULL);
|
||||
@ -815,7 +821,10 @@ class WebRtcSessionTest : public testing::Test {
|
||||
|
||||
// Adding firewall rule to block ping requests, which should cause
|
||||
// transport channel failure.
|
||||
fss_->AddRule(false, talk_base::FP_ANY, talk_base::FD_ANY, kClientAddr1);
|
||||
fss_->AddRule(false,
|
||||
talk_base::FP_ANY,
|
||||
talk_base::FD_ANY,
|
||||
talk_base::SocketAddress(kClientAddrHost1, kClientAddrPort));
|
||||
EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionDisconnected,
|
||||
observer_.ice_connection_state_,
|
||||
kIceCandidatesTimeout);
|
||||
@ -840,7 +849,10 @@ class WebRtcSessionTest : public testing::Test {
|
||||
|
||||
// Adds CN codecs to FakeMediaEngine and MediaDescriptionFactory.
|
||||
void AddCNCodecs() {
|
||||
// Add kTelephoneEventCodec for dtmf test.
|
||||
const cricket::AudioCodec kCNCodec1(102, "CN", 8000, 0, 1, 0);
|
||||
const cricket::AudioCodec kCNCodec2(103, "CN", 16000, 0, 1, 0);
|
||||
|
||||
// Add kCNCodec for dtmf test.
|
||||
std::vector<cricket::AudioCodec> codecs = media_engine_->audio_codecs();;
|
||||
codecs.push_back(kCNCodec1);
|
||||
codecs.push_back(kCNCodec2);
|
||||
@ -918,6 +930,7 @@ class WebRtcSessionTest : public testing::Test {
|
||||
talk_base::scoped_ptr<talk_base::VirtualSocketServer> vss_;
|
||||
talk_base::scoped_ptr<talk_base::FirewallSocketServer> fss_;
|
||||
talk_base::SocketServerScope ss_scope_;
|
||||
talk_base::SocketAddress stun_socket_addr_;
|
||||
cricket::TestStunServer stun_server_;
|
||||
talk_base::FakeNetworkManager network_manager_;
|
||||
cricket::BasicPortAllocator allocator_;
|
||||
@ -941,7 +954,7 @@ TEST_F(WebRtcSessionTest, TestInitializeWithDtls) {
|
||||
// Verifies that WebRtcSession uses SEC_REQUIRED by default.
|
||||
TEST_F(WebRtcSessionTest, TestDefaultSetSecurePolicy) {
|
||||
Init(NULL);
|
||||
EXPECT_EQ(cricket::SEC_REQUIRED, session_->secure_policy());
|
||||
EXPECT_EQ(cricket::SEC_REQUIRED, session_->SecurePolicy());
|
||||
}
|
||||
|
||||
TEST_F(WebRtcSessionTest, TestSessionCandidates) {
|
||||
@ -959,8 +972,8 @@ TEST_F(WebRtcSessionTest, TestSessionCandidatesWithBundleRtcpMux) {
|
||||
}
|
||||
|
||||
TEST_F(WebRtcSessionTest, TestMultihomeCandidates) {
|
||||
AddInterface(kClientAddr1);
|
||||
AddInterface(kClientAddr2);
|
||||
AddInterface(talk_base::SocketAddress(kClientAddrHost1, kClientAddrPort));
|
||||
AddInterface(talk_base::SocketAddress(kClientAddrHost2, kClientAddrPort));
|
||||
Init(NULL);
|
||||
mediastream_signaling_.SendAudioVideoStream1();
|
||||
InitiateCall();
|
||||
@ -970,13 +983,16 @@ TEST_F(WebRtcSessionTest, TestMultihomeCandidates) {
|
||||
}
|
||||
|
||||
TEST_F(WebRtcSessionTest, TestStunError) {
|
||||
AddInterface(kClientAddr1);
|
||||
AddInterface(kClientAddr2);
|
||||
fss_->AddRule(false, talk_base::FP_UDP, talk_base::FD_ANY, kClientAddr1);
|
||||
AddInterface(talk_base::SocketAddress(kClientAddrHost1, kClientAddrPort));
|
||||
AddInterface(talk_base::SocketAddress(kClientAddrHost2, kClientAddrPort));
|
||||
fss_->AddRule(false,
|
||||
talk_base::FP_UDP,
|
||||
talk_base::FD_ANY,
|
||||
talk_base::SocketAddress(kClientAddrHost1, kClientAddrPort));
|
||||
Init(NULL);
|
||||
mediastream_signaling_.SendAudioVideoStream1();
|
||||
InitiateCall();
|
||||
// Since kClientAddr1 is blocked, not expecting stun candidates for it.
|
||||
// Since kClientAddrHost1 is blocked, not expecting stun candidates for it.
|
||||
EXPECT_TRUE_WAIT(observer_.oncandidatesready_, kIceCandidatesTimeout);
|
||||
EXPECT_EQ(6u, observer_.mline_0_candidates_.size());
|
||||
EXPECT_EQ(6u, observer_.mline_1_candidates_.size());
|
||||
@ -1420,7 +1436,7 @@ TEST_F(WebRtcSessionTest, TestRemoteCandidatesAddedToSessionDescription) {
|
||||
// Test that local candidates are added to the local session description and
|
||||
// that they are retained if the local session description is changed.
|
||||
TEST_F(WebRtcSessionTest, TestLocalCandidatesAddedToSessionDescription) {
|
||||
AddInterface(kClientAddr1);
|
||||
AddInterface(talk_base::SocketAddress(kClientAddrHost1, kClientAddrPort));
|
||||
Init(NULL);
|
||||
mediastream_signaling_.SendAudioVideoStream1();
|
||||
CreateAndSetRemoteOfferAndLocalAnswer();
|
||||
@ -1484,7 +1500,7 @@ TEST_F(WebRtcSessionTest, TestSetRemoteSessionDescriptionWithCandidates) {
|
||||
// Test that offers and answers contains ice candidates when Ice candidates have
|
||||
// been gathered.
|
||||
TEST_F(WebRtcSessionTest, TestSetLocalAndRemoteDescriptionWithCandidates) {
|
||||
AddInterface(kClientAddr1);
|
||||
AddInterface(talk_base::SocketAddress(kClientAddrHost1, kClientAddrPort));
|
||||
Init(NULL);
|
||||
mediastream_signaling_.SendAudioVideoStream1();
|
||||
// Ice is started but candidates are not provided until SetLocalDescription
|
||||
|
@ -33,10 +33,10 @@
|
||||
#include "talk/app/webrtc/mediastreamsignaling.h"
|
||||
#include "talk/app/webrtc/webrtcsession.h"
|
||||
|
||||
using cricket::MediaSessionOptions;
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
|
||||
static const char kFailedDueToIdentityFailed[] =
|
||||
" failed because DTLS identity request failed";
|
||||
|
||||
@ -46,25 +46,24 @@ static const char kWebRTCIdentityName[] = "WebRTC";
|
||||
|
||||
static const uint64 kInitSessionVersion = 2;
|
||||
|
||||
typedef cricket::MediaSessionOptions::Stream Stream;
|
||||
typedef cricket::MediaSessionOptions::Streams Streams;
|
||||
|
||||
static bool CompareStream(const Stream& stream1, const Stream& stream2) {
|
||||
return (stream1.id < stream2.id);
|
||||
static bool CompareStream(const MediaSessionOptions::Stream& stream1,
|
||||
const MediaSessionOptions::Stream& stream2) {
|
||||
return stream1.id < stream2.id;
|
||||
}
|
||||
|
||||
static bool SameId(const Stream& stream1, const Stream& stream2) {
|
||||
return (stream1.id == stream2.id);
|
||||
static bool SameId(const MediaSessionOptions::Stream& stream1,
|
||||
const MediaSessionOptions::Stream& stream2) {
|
||||
return stream1.id == stream2.id;
|
||||
}
|
||||
|
||||
// Checks if each Stream within the |streams| has unique id.
|
||||
static bool ValidStreams(const Streams& streams) {
|
||||
Streams sorted_streams = streams;
|
||||
static bool ValidStreams(const MediaSessionOptions::Streams& streams) {
|
||||
MediaSessionOptions::Streams sorted_streams = streams;
|
||||
std::sort(sorted_streams.begin(), sorted_streams.end(), CompareStream);
|
||||
Streams::iterator it =
|
||||
MediaSessionOptions::Streams::iterator it =
|
||||
std::adjacent_find(sorted_streams.begin(), sorted_streams.end(),
|
||||
SameId);
|
||||
return (it == sorted_streams.end());
|
||||
return it == sorted_streams.end();
|
||||
}
|
||||
|
||||
enum {
|
||||
@ -83,7 +82,6 @@ struct CreateSessionDescriptionMsg : public talk_base::MessageData {
|
||||
std::string error;
|
||||
talk_base::scoped_ptr<webrtc::SessionDescriptionInterface> description;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
@ -130,33 +128,35 @@ WebRtcSessionDescriptionFactory::WebRtcSessionDescriptionFactory(
|
||||
transport_desc_factory_.set_protocol(cricket::ICEPROTO_HYBRID);
|
||||
session_desc_factory_.set_add_legacy_streams(false);
|
||||
// By default SRTP-SDES is enabled in WebRtc.
|
||||
set_secure(cricket::SEC_REQUIRED);
|
||||
SetSecure(cricket::SEC_REQUIRED);
|
||||
|
||||
if (dtls_enabled) {
|
||||
if (identity_service_.get()) {
|
||||
identity_request_observer_ =
|
||||
new talk_base::RefCountedObject<WebRtcIdentityRequestObserver>();
|
||||
if (!dtls_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
identity_request_observer_->SignalRequestFailed.connect(
|
||||
this, &WebRtcSessionDescriptionFactory::OnIdentityRequestFailed);
|
||||
identity_request_observer_->SignalIdentityReady.connect(
|
||||
this, &WebRtcSessionDescriptionFactory::OnIdentityReady);
|
||||
if (identity_service_.get()) {
|
||||
identity_request_observer_ =
|
||||
new talk_base::RefCountedObject<WebRtcIdentityRequestObserver>();
|
||||
|
||||
if (identity_service_->RequestIdentity(kWebRTCIdentityName,
|
||||
kWebRTCIdentityName,
|
||||
identity_request_observer_)) {
|
||||
LOG(LS_VERBOSE) << "DTLS-SRTP enabled; sent DTLS identity request.";
|
||||
identity_request_state_ = IDENTITY_WAITING;
|
||||
} else {
|
||||
LOG(LS_ERROR) << "Failed to send DTLS identity request.";
|
||||
identity_request_state_ = IDENTITY_FAILED;
|
||||
}
|
||||
} else {
|
||||
identity_request_observer_->SignalRequestFailed.connect(
|
||||
this, &WebRtcSessionDescriptionFactory::OnIdentityRequestFailed);
|
||||
identity_request_observer_->SignalIdentityReady.connect(
|
||||
this, &WebRtcSessionDescriptionFactory::OnIdentityReady);
|
||||
|
||||
if (identity_service_->RequestIdentity(kWebRTCIdentityName,
|
||||
kWebRTCIdentityName,
|
||||
identity_request_observer_)) {
|
||||
LOG(LS_VERBOSE) << "DTLS-SRTP enabled; sent DTLS identity request.";
|
||||
identity_request_state_ = IDENTITY_WAITING;
|
||||
// Do not generate the identity in the constructor since the caller has
|
||||
// not got a chance to connect to SignalIdentityReady.
|
||||
signaling_thread_->Post(this, MSG_GENERATE_IDENTITY, NULL);
|
||||
} else {
|
||||
LOG(LS_ERROR) << "Failed to send DTLS identity request.";
|
||||
identity_request_state_ = IDENTITY_FAILED;
|
||||
}
|
||||
} else {
|
||||
identity_request_state_ = IDENTITY_WAITING;
|
||||
// Do not generate the identity in the constructor since the caller has
|
||||
// not got a chance to connect to SignalIdentityReady.
|
||||
signaling_thread_->Post(this, MSG_GENERATE_IDENTITY, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@ -261,19 +261,15 @@ void WebRtcSessionDescriptionFactory::CreateAnswer(
|
||||
}
|
||||
}
|
||||
|
||||
void WebRtcSessionDescriptionFactory::set_secure(
|
||||
void WebRtcSessionDescriptionFactory::SetSecure(
|
||||
cricket::SecureMediaPolicy secure_policy) {
|
||||
session_desc_factory_.set_secure(secure_policy);
|
||||
}
|
||||
|
||||
cricket::SecureMediaPolicy WebRtcSessionDescriptionFactory::secure() const {
|
||||
cricket::SecureMediaPolicy WebRtcSessionDescriptionFactory::Secure() const {
|
||||
return session_desc_factory_.secure();
|
||||
}
|
||||
|
||||
bool WebRtcSessionDescriptionFactory::waiting_for_identity() const {
|
||||
return identity_request_state_ == IDENTITY_WAITING;
|
||||
}
|
||||
|
||||
void WebRtcSessionDescriptionFactory::OnMessage(talk_base::Message* msg) {
|
||||
switch (msg->message_id) {
|
||||
case MSG_CREATE_SESSIONDESCRIPTION_SUCCESS: {
|
||||
@ -450,5 +446,4 @@ void WebRtcSessionDescriptionFactory::SetIdentity(
|
||||
create_session_description_requests_.pop();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
@ -34,21 +34,17 @@
|
||||
#include "talk/session/media/mediasession.h"
|
||||
|
||||
namespace cricket {
|
||||
|
||||
class ChannelManager;
|
||||
class TransportDescriptionFactory;
|
||||
|
||||
} // namespace cricket
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class CreateSessionDescriptionObserver;
|
||||
class MediaConstraintsInterface;
|
||||
class MediaStreamSignaling;
|
||||
class SessionDescriptionInterface;
|
||||
class WebRtcSession;
|
||||
|
||||
|
||||
// DTLS identity request callback class.
|
||||
class WebRtcIdentityRequestObserver : public DTLSIdentityRequestObserver,
|
||||
public sigslot::has_slots<> {
|
||||
@ -116,13 +112,15 @@ class WebRtcSessionDescriptionFactory : public talk_base::MessageHandler,
|
||||
CreateSessionDescriptionObserver* observer,
|
||||
const MediaConstraintsInterface* constraints);
|
||||
|
||||
void set_secure(cricket::SecureMediaPolicy secure_policy);
|
||||
cricket::SecureMediaPolicy secure() const;
|
||||
void SetSecure(cricket::SecureMediaPolicy secure_policy);
|
||||
cricket::SecureMediaPolicy Secure() const;
|
||||
|
||||
sigslot::signal1<talk_base::SSLIdentity*> SignalIdentityReady;
|
||||
|
||||
// For testing.
|
||||
bool waiting_for_identity() const;
|
||||
bool waiting_for_identity() const {
|
||||
return identity_request_state_ == IDENTITY_WAITING;
|
||||
}
|
||||
|
||||
private:
|
||||
enum IdentityRequestState {
|
||||
@ -166,7 +164,6 @@ class WebRtcSessionDescriptionFactory : public talk_base::MessageHandler,
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(WebRtcSessionDescriptionFactory);
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // TALK_APP_WEBRTC_WEBRTCSESSIONDESCRIPTIONFACTORY_H_
|
||||
|
@ -383,6 +383,7 @@
|
||||
# 'app/webrtc/mediastreamhandler_unittest.cc',
|
||||
'app/webrtc/mediastreamsignaling_unittest.cc',
|
||||
'app/webrtc/peerconnection_unittest.cc',
|
||||
'app/webrtc/peerconnectionendtoend_unittest.cc',
|
||||
'app/webrtc/peerconnectionfactory_unittest.cc',
|
||||
'app/webrtc/peerconnectioninterface_unittest.cc',
|
||||
# 'app/webrtc/peerconnectionproxy_unittest.cc',
|
||||
@ -397,6 +398,8 @@
|
||||
'app/webrtc/test/fakeperiodicvideocapturer.h',
|
||||
'app/webrtc/test/fakevideotrackrenderer.h',
|
||||
'app/webrtc/test/mockpeerconnectionobservers.h',
|
||||
'app/webrtc/test/peerconnectiontestwrapper.h',
|
||||
'app/webrtc/test/peerconnectiontestwrapper.cc',
|
||||
'app/webrtc/test/testsdpstrings.h',
|
||||
'app/webrtc/videosource_unittest.cc',
|
||||
'app/webrtc/videotrack_unittest.cc',
|
||||
|
@ -109,7 +109,7 @@ class CoordinatedVideoAdapter
|
||||
: public VideoAdapter, public sigslot::has_slots<> {
|
||||
public:
|
||||
enum AdaptRequest { UPGRADE, KEEP, DOWNGRADE };
|
||||
enum {
|
||||
enum AdaptReasonEnum {
|
||||
ADAPTREASON_CPU = 1,
|
||||
ADAPTREASON_BANDWIDTH = 2,
|
||||
ADAPTREASON_VIEW = 4
|
||||
|
@ -252,6 +252,19 @@ class FakeWebRtcVoiceEngine
|
||||
true);
|
||||
}
|
||||
}
|
||||
int AddChannel() {
|
||||
if (fail_create_channel_) {
|
||||
return -1;
|
||||
}
|
||||
Channel* ch = new Channel();
|
||||
for (int i = 0; i < NumOfCodecs(); ++i) {
|
||||
webrtc::CodecInst codec;
|
||||
GetCodec(i, codec);
|
||||
ch->recv_codecs.push_back(codec);
|
||||
}
|
||||
channels_[++last_channel_] = ch;
|
||||
return last_channel_;
|
||||
}
|
||||
|
||||
WEBRTC_STUB(Release, ());
|
||||
|
||||
@ -275,18 +288,13 @@ class FakeWebRtcVoiceEngine
|
||||
return NULL;
|
||||
}
|
||||
WEBRTC_FUNC(CreateChannel, ()) {
|
||||
if (fail_create_channel_) {
|
||||
return -1;
|
||||
}
|
||||
Channel* ch = new Channel();
|
||||
for (int i = 0; i < NumOfCodecs(); ++i) {
|
||||
webrtc::CodecInst codec;
|
||||
GetCodec(i, codec);
|
||||
ch->recv_codecs.push_back(codec);
|
||||
}
|
||||
channels_[++last_channel_] = ch;
|
||||
return last_channel_;
|
||||
return AddChannel();
|
||||
}
|
||||
#ifdef USE_WEBRTC_DEV_BRANCH
|
||||
WEBRTC_FUNC(CreateChannel, (const webrtc::Config& /*config*/)) {
|
||||
return AddChannel();
|
||||
}
|
||||
#endif
|
||||
WEBRTC_FUNC(DeleteChannel, (int channel)) {
|
||||
WEBRTC_CHECK_CHANNEL(channel);
|
||||
delete channels_[channel];
|
||||
|
@ -998,10 +998,11 @@ bool Session::TerminateWithReason(const std::string& reason) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Session::SendInfoMessage(const XmlElements& elems) {
|
||||
bool Session::SendInfoMessage(const XmlElements& elems,
|
||||
const std::string& remote_name) {
|
||||
ASSERT(signaling_thread()->IsCurrent());
|
||||
SessionError error;
|
||||
if (!SendMessage(ACTION_SESSION_INFO, elems, &error)) {
|
||||
if (!SendMessage(ACTION_SESSION_INFO, elems, remote_name, &error)) {
|
||||
LOG(LS_ERROR) << "Could not send info message " << error.text;
|
||||
return false;
|
||||
}
|
||||
@ -1644,11 +1645,16 @@ bool Session::SendAllUnsentTransportInfoMessages(SessionError* error) {
|
||||
|
||||
bool Session::SendMessage(ActionType type, const XmlElements& action_elems,
|
||||
SessionError* error) {
|
||||
return SendMessage(type, action_elems, remote_name(), error);
|
||||
}
|
||||
|
||||
bool Session::SendMessage(ActionType type, const XmlElements& action_elems,
|
||||
const std::string& remote_name, SessionError* error) {
|
||||
talk_base::scoped_ptr<buzz::XmlElement> stanza(
|
||||
new buzz::XmlElement(buzz::QN_IQ));
|
||||
|
||||
SessionMessage msg(current_protocol_, type, id(), initiator_name());
|
||||
msg.to = remote_name();
|
||||
msg.to = remote_name;
|
||||
WriteSessionMessage(msg, action_elems, stanza.get());
|
||||
|
||||
SignalOutgoingMessage(this, stanza.get());
|
||||
|
@ -584,7 +584,8 @@ class Session : public BaseSession {
|
||||
// arbitrary XML messages, which are called "info" messages. Sending
|
||||
// takes ownership of the given elements. The signal does not; the
|
||||
// parent element will be deleted after the signal.
|
||||
bool SendInfoMessage(const XmlElements& elems);
|
||||
bool SendInfoMessage(const XmlElements& elems,
|
||||
const std::string& remote_name);
|
||||
bool SendDescriptionInfoMessage(const ContentInfos& contents);
|
||||
sigslot::signal2<Session*, const buzz::XmlElement*> SignalInfoMessage;
|
||||
|
||||
@ -638,7 +639,7 @@ class Session : public BaseSession {
|
||||
bool ResendAllTransportInfoMessages(SessionError* error);
|
||||
bool SendAllUnsentTransportInfoMessages(SessionError* error);
|
||||
|
||||
// Both versions of SendMessage send a message of the given type to
|
||||
// All versions of SendMessage send a message of the given type to
|
||||
// the other client. Can pass either a set of elements or an
|
||||
// "action", which must have a WriteSessionAction method to go along
|
||||
// with it. Sending with an action supports sending a "hybrid"
|
||||
@ -648,6 +649,10 @@ class Session : public BaseSession {
|
||||
// Takes ownership of action_elems.
|
||||
bool SendMessage(ActionType type, const XmlElements& action_elems,
|
||||
SessionError* error);
|
||||
// Sends a messge, but overrides the remote name.
|
||||
bool SendMessage(ActionType type, const XmlElements& action_elems,
|
||||
const std::string& remote_name,
|
||||
SessionError* error);
|
||||
// When passing an action, may be Hybrid protocol.
|
||||
template <typename Action>
|
||||
bool SendMessage(ActionType type, const Action& action,
|
||||
|
@ -186,7 +186,7 @@ bool Call::SendViewRequest(Session* session,
|
||||
return false;
|
||||
}
|
||||
|
||||
return session->SendInfoMessage(elems);
|
||||
return session->SendInfoMessage(elems, session->remote_name());
|
||||
}
|
||||
|
||||
void Call::SetLocalRenderer(VideoRenderer* renderer) {
|
||||
|
@ -22,6 +22,8 @@ JsepPeerConnectionP2PTestClient.LocalP2PTestWithoutMsid
|
||||
JsepPeerConnectionP2PTestClient.LocalP2PTestWithVideoDecoderFactory
|
||||
JsepPeerConnectionP2PTestClient.RegisterDataChannelObserver
|
||||
JsepPeerConnectionP2PTestClient.UpdateOfferWithRejectedContent
|
||||
PeerConnectionEndToEndTest.Call
|
||||
PeerConnectionEndToEndTest.CallWithLegacySdp
|
||||
PeerConnectionInterfaceTest.DataChannelCloseWhenPeerConnectionClose
|
||||
PeerConnectionInterfaceTest.TestDataChannel
|
||||
PeerConnectionInterfaceTest.TestSendBinaryOnRtpDataChannel
|
||||
|
@ -21,6 +21,8 @@ JsepPeerConnectionP2PTestClient.LocalP2PTestWithVideoDecoderFactory
|
||||
JsepPeerConnectionP2PTestClient.RegisterDataChannelObserver
|
||||
JsepPeerConnectionP2PTestClient.UpdateOfferWithRejectedContent
|
||||
PeerConnectionInterfaceTest.DataChannelCloseWhenPeerConnectionClose
|
||||
PeerConnectionEndToEndTest.Call
|
||||
PeerConnectionEndToEndTest.CallWithLegacySdp
|
||||
PeerConnectionInterfaceTest.ReceiveFireFoxOffer
|
||||
PeerConnectionInterfaceTest.TestDataChannel
|
||||
PeerConnectionInterfaceTest.TestSendBinaryOnRtpDataChannel
|
||||
|
Loading…
x
Reference in New Issue
Block a user