1 /* 2 * libjingle 3 * Copyright 2013 Google Inc. 4 * 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 28 #include <utility> 29 30 #include "talk/app/webrtc/test/fakedtlsidentitystore.h" 31 #include "talk/app/webrtc/test/fakeperiodicvideocapturer.h" 32 #include "talk/app/webrtc/test/mockpeerconnectionobservers.h" 33 #include "talk/app/webrtc/test/peerconnectiontestwrapper.h" 34 #include "talk/app/webrtc/videosourceinterface.h" 35 #include "webrtc/base/gunit.h" 36 #include "webrtc/p2p/client/fakeportallocator.h" 37 38 static const char kStreamLabelBase[] = "stream_label"; 39 static const char kVideoTrackLabelBase[] = "video_track"; 40 static const char kAudioTrackLabelBase[] = "audio_track"; 41 static const int kMaxWait = 10000; 42 static const int kTestAudioFrameCount = 3; 43 static const int kTestVideoFrameCount = 3; 44 45 using webrtc::FakeConstraints; 46 using webrtc::FakeVideoTrackRenderer; 47 using webrtc::IceCandidateInterface; 48 using webrtc::MediaConstraintsInterface; 49 using webrtc::MediaStreamInterface; 50 using webrtc::MockSetSessionDescriptionObserver; 51 using webrtc::PeerConnectionInterface; 52 using webrtc::SessionDescriptionInterface; 53 using webrtc::VideoTrackInterface; 54 55 void PeerConnectionTestWrapper::Connect(PeerConnectionTestWrapper* caller, 56 PeerConnectionTestWrapper* callee) { 57 caller->SignalOnIceCandidateReady.connect( 58 callee, &PeerConnectionTestWrapper::AddIceCandidate); 59 callee->SignalOnIceCandidateReady.connect( 60 caller, &PeerConnectionTestWrapper::AddIceCandidate); 61 62 caller->SignalOnSdpReady.connect( 63 callee, &PeerConnectionTestWrapper::ReceiveOfferSdp); 64 callee->SignalOnSdpReady.connect( 65 caller, &PeerConnectionTestWrapper::ReceiveAnswerSdp); 66 } 67 68 PeerConnectionTestWrapper::PeerConnectionTestWrapper(const std::string& name) 69 : name_(name) {} 70 71 PeerConnectionTestWrapper::~PeerConnectionTestWrapper() {} 72 73 bool PeerConnectionTestWrapper::CreatePc( 74 const MediaConstraintsInterface* constraints) { 75 rtc::scoped_ptr<cricket::PortAllocator> port_allocator( 76 new cricket::FakePortAllocator(rtc::Thread::Current(), nullptr)); 77 78 fake_audio_capture_module_ = FakeAudioCaptureModule::Create(); 79 if (fake_audio_capture_module_ == NULL) { 80 return false; 81 } 82 83 peer_connection_factory_ = webrtc::CreatePeerConnectionFactory( 84 rtc::Thread::Current(), rtc::Thread::Current(), 85 fake_audio_capture_module_, NULL, NULL); 86 if (!peer_connection_factory_) { 87 return false; 88 } 89 90 // CreatePeerConnection with RTCConfiguration. 91 webrtc::PeerConnectionInterface::RTCConfiguration config; 92 webrtc::PeerConnectionInterface::IceServer ice_server; 93 ice_server.uri = "stun:stun.l.google.com:19302"; 94 config.servers.push_back(ice_server); 95 rtc::scoped_ptr<webrtc::DtlsIdentityStoreInterface> dtls_identity_store( 96 rtc::SSLStreamAdapter::HaveDtlsSrtp() ? 97 new FakeDtlsIdentityStore() : nullptr); 98 peer_connection_ = peer_connection_factory_->CreatePeerConnection( 99 config, constraints, std::move(port_allocator), 100 std::move(dtls_identity_store), this); 101 102 return peer_connection_.get() != NULL; 103 } 104 105 rtc::scoped_refptr<webrtc::DataChannelInterface> 106 PeerConnectionTestWrapper::CreateDataChannel( 107 const std::string& label, 108 const webrtc::DataChannelInit& init) { 109 return peer_connection_->CreateDataChannel(label, &init); 110 } 111 112 void PeerConnectionTestWrapper::OnAddStream(MediaStreamInterface* stream) { 113 LOG(LS_INFO) << "PeerConnectionTestWrapper " << name_ 114 << ": OnAddStream"; 115 // TODO(ronghuawu): support multiple streams. 116 if (stream->GetVideoTracks().size() > 0) { 117 renderer_.reset(new FakeVideoTrackRenderer(stream->GetVideoTracks()[0])); 118 } 119 } 120 121 void PeerConnectionTestWrapper::OnIceCandidate( 122 const IceCandidateInterface* candidate) { 123 std::string sdp; 124 EXPECT_TRUE(candidate->ToString(&sdp)); 125 // Give the user a chance to modify sdp for testing. 126 SignalOnIceCandidateCreated(&sdp); 127 SignalOnIceCandidateReady(candidate->sdp_mid(), candidate->sdp_mline_index(), 128 sdp); 129 } 130 131 void PeerConnectionTestWrapper::OnDataChannel( 132 webrtc::DataChannelInterface* data_channel) { 133 SignalOnDataChannel(data_channel); 134 } 135 136 void PeerConnectionTestWrapper::OnSuccess(SessionDescriptionInterface* desc) { 137 // This callback should take the ownership of |desc|. 138 rtc::scoped_ptr<SessionDescriptionInterface> owned_desc(desc); 139 std::string sdp; 140 EXPECT_TRUE(desc->ToString(&sdp)); 141 142 LOG(LS_INFO) << "PeerConnectionTestWrapper " << name_ 143 << ": " << desc->type() << " sdp created: " << sdp; 144 145 // Give the user a chance to modify sdp for testing. 146 SignalOnSdpCreated(&sdp); 147 148 SetLocalDescription(desc->type(), sdp); 149 150 SignalOnSdpReady(sdp); 151 } 152 153 void PeerConnectionTestWrapper::CreateOffer( 154 const MediaConstraintsInterface* constraints) { 155 LOG(LS_INFO) << "PeerConnectionTestWrapper " << name_ 156 << ": CreateOffer."; 157 peer_connection_->CreateOffer(this, constraints); 158 } 159 160 void PeerConnectionTestWrapper::CreateAnswer( 161 const MediaConstraintsInterface* constraints) { 162 LOG(LS_INFO) << "PeerConnectionTestWrapper " << name_ 163 << ": CreateAnswer."; 164 peer_connection_->CreateAnswer(this, constraints); 165 } 166 167 void PeerConnectionTestWrapper::ReceiveOfferSdp(const std::string& sdp) { 168 SetRemoteDescription(SessionDescriptionInterface::kOffer, sdp); 169 CreateAnswer(NULL); 170 } 171 172 void PeerConnectionTestWrapper::ReceiveAnswerSdp(const std::string& sdp) { 173 SetRemoteDescription(SessionDescriptionInterface::kAnswer, sdp); 174 } 175 176 void PeerConnectionTestWrapper::SetLocalDescription(const std::string& type, 177 const std::string& sdp) { 178 LOG(LS_INFO) << "PeerConnectionTestWrapper " << name_ 179 << ": SetLocalDescription " << type << " " << sdp; 180 181 rtc::scoped_refptr<MockSetSessionDescriptionObserver> 182 observer(new rtc::RefCountedObject< 183 MockSetSessionDescriptionObserver>()); 184 peer_connection_->SetLocalDescription( 185 observer, webrtc::CreateSessionDescription(type, sdp, NULL)); 186 } 187 188 void PeerConnectionTestWrapper::SetRemoteDescription(const std::string& type, 189 const std::string& sdp) { 190 LOG(LS_INFO) << "PeerConnectionTestWrapper " << name_ 191 << ": SetRemoteDescription " << type << " " << sdp; 192 193 rtc::scoped_refptr<MockSetSessionDescriptionObserver> 194 observer(new rtc::RefCountedObject< 195 MockSetSessionDescriptionObserver>()); 196 peer_connection_->SetRemoteDescription( 197 observer, webrtc::CreateSessionDescription(type, sdp, NULL)); 198 } 199 200 void PeerConnectionTestWrapper::AddIceCandidate(const std::string& sdp_mid, 201 int sdp_mline_index, 202 const std::string& candidate) { 203 rtc::scoped_ptr<webrtc::IceCandidateInterface> owned_candidate( 204 webrtc::CreateIceCandidate(sdp_mid, sdp_mline_index, candidate, NULL)); 205 EXPECT_TRUE(peer_connection_->AddIceCandidate(owned_candidate.get())); 206 } 207 208 void PeerConnectionTestWrapper::WaitForCallEstablished() { 209 WaitForConnection(); 210 WaitForAudio(); 211 WaitForVideo(); 212 } 213 214 void PeerConnectionTestWrapper::WaitForConnection() { 215 EXPECT_TRUE_WAIT(CheckForConnection(), kMaxWait); 216 LOG(LS_INFO) << "PeerConnectionTestWrapper " << name_ 217 << ": Connected."; 218 } 219 220 bool PeerConnectionTestWrapper::CheckForConnection() { 221 return (peer_connection_->ice_connection_state() == 222 PeerConnectionInterface::kIceConnectionConnected) || 223 (peer_connection_->ice_connection_state() == 224 PeerConnectionInterface::kIceConnectionCompleted); 225 } 226 227 void PeerConnectionTestWrapper::WaitForAudio() { 228 EXPECT_TRUE_WAIT(CheckForAudio(), kMaxWait); 229 LOG(LS_INFO) << "PeerConnectionTestWrapper " << name_ 230 << ": Got enough audio frames."; 231 } 232 233 bool PeerConnectionTestWrapper::CheckForAudio() { 234 return (fake_audio_capture_module_->frames_received() >= 235 kTestAudioFrameCount); 236 } 237 238 void PeerConnectionTestWrapper::WaitForVideo() { 239 EXPECT_TRUE_WAIT(CheckForVideo(), kMaxWait); 240 LOG(LS_INFO) << "PeerConnectionTestWrapper " << name_ 241 << ": Got enough video frames."; 242 } 243 244 bool PeerConnectionTestWrapper::CheckForVideo() { 245 if (!renderer_) { 246 return false; 247 } 248 return (renderer_->num_rendered_frames() >= kTestVideoFrameCount); 249 } 250 251 void PeerConnectionTestWrapper::GetAndAddUserMedia( 252 bool audio, const webrtc::FakeConstraints& audio_constraints, 253 bool video, const webrtc::FakeConstraints& video_constraints) { 254 rtc::scoped_refptr<webrtc::MediaStreamInterface> stream = 255 GetUserMedia(audio, audio_constraints, video, video_constraints); 256 EXPECT_TRUE(peer_connection_->AddStream(stream)); 257 } 258 259 rtc::scoped_refptr<webrtc::MediaStreamInterface> 260 PeerConnectionTestWrapper::GetUserMedia( 261 bool audio, const webrtc::FakeConstraints& audio_constraints, 262 bool video, const webrtc::FakeConstraints& video_constraints) { 263 std::string label = kStreamLabelBase + 264 rtc::ToString<int>( 265 static_cast<int>(peer_connection_->local_streams()->count())); 266 rtc::scoped_refptr<webrtc::MediaStreamInterface> stream = 267 peer_connection_factory_->CreateLocalMediaStream(label); 268 269 if (audio) { 270 FakeConstraints constraints = audio_constraints; 271 // Disable highpass filter so that we can get all the test audio frames. 272 constraints.AddMandatory( 273 MediaConstraintsInterface::kHighpassFilter, false); 274 rtc::scoped_refptr<webrtc::AudioSourceInterface> source = 275 peer_connection_factory_->CreateAudioSource(&constraints); 276 rtc::scoped_refptr<webrtc::AudioTrackInterface> audio_track( 277 peer_connection_factory_->CreateAudioTrack(kAudioTrackLabelBase, 278 source)); 279 stream->AddTrack(audio_track); 280 } 281 282 if (video) { 283 // Set max frame rate to 10fps to reduce the risk of the tests to be flaky. 284 FakeConstraints constraints = video_constraints; 285 constraints.SetMandatoryMaxFrameRate(10); 286 287 rtc::scoped_refptr<webrtc::VideoSourceInterface> source = 288 peer_connection_factory_->CreateVideoSource( 289 new webrtc::FakePeriodicVideoCapturer(), &constraints); 290 std::string videotrack_label = label + kVideoTrackLabelBase; 291 rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track( 292 peer_connection_factory_->CreateVideoTrack(videotrack_label, source)); 293 294 stream->AddTrack(video_track); 295 } 296 return stream; 297 } 298