1 /*
2 * Copyright 2013 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "pc/test/peer_connection_test_wrapper.h"
12
13 #include <stddef.h>
14
15 #include <memory>
16 #include <string>
17 #include <utility>
18 #include <vector>
19
20 #include "absl/types/optional.h"
21 #include "api/audio/audio_mixer.h"
22 #include "api/create_peerconnection_factory.h"
23 #include "api/sequence_checker.h"
24 #include "api/video_codecs/builtin_video_decoder_factory.h"
25 #include "api/video_codecs/builtin_video_encoder_factory.h"
26 #include "api/video_codecs/video_decoder_factory.h"
27 #include "api/video_codecs/video_encoder_factory.h"
28 #include "modules/audio_device/include/audio_device.h"
29 #include "modules/audio_processing/include/audio_processing.h"
30 #include "p2p/base/fake_port_allocator.h"
31 #include "p2p/base/port_allocator.h"
32 #include "pc/test/fake_periodic_video_source.h"
33 #include "pc/test/fake_periodic_video_track_source.h"
34 #include "pc/test/fake_rtc_certificate_generator.h"
35 #include "pc/test/mock_peer_connection_observers.h"
36 #include "rtc_base/gunit.h"
37 #include "rtc_base/logging.h"
38 #include "rtc_base/rtc_certificate_generator.h"
39 #include "rtc_base/string_encode.h"
40 #include "rtc_base/time_utils.h"
41 #include "test/gtest.h"
42
43 using webrtc::FakeVideoTrackRenderer;
44 using webrtc::IceCandidateInterface;
45 using webrtc::MediaStreamInterface;
46 using webrtc::MediaStreamTrackInterface;
47 using webrtc::MockSetSessionDescriptionObserver;
48 using webrtc::PeerConnectionInterface;
49 using webrtc::RtpReceiverInterface;
50 using webrtc::SdpType;
51 using webrtc::SessionDescriptionInterface;
52 using webrtc::VideoTrackInterface;
53
54 namespace {
55 const char kStreamIdBase[] = "stream_id";
56 const char kVideoTrackLabelBase[] = "video_track";
57 const char kAudioTrackLabelBase[] = "audio_track";
58 constexpr int kMaxWait = 10000;
59 constexpr int kTestAudioFrameCount = 3;
60 constexpr int kTestVideoFrameCount = 3;
61 } // namespace
62
Connect(PeerConnectionTestWrapper * caller,PeerConnectionTestWrapper * callee)63 void PeerConnectionTestWrapper::Connect(PeerConnectionTestWrapper* caller,
64 PeerConnectionTestWrapper* callee) {
65 caller->SignalOnIceCandidateReady.connect(
66 callee, &PeerConnectionTestWrapper::AddIceCandidate);
67 callee->SignalOnIceCandidateReady.connect(
68 caller, &PeerConnectionTestWrapper::AddIceCandidate);
69
70 caller->SignalOnSdpReady.connect(callee,
71 &PeerConnectionTestWrapper::ReceiveOfferSdp);
72 callee->SignalOnSdpReady.connect(
73 caller, &PeerConnectionTestWrapper::ReceiveAnswerSdp);
74 }
75
PeerConnectionTestWrapper(const std::string & name,rtc::SocketServer * socket_server,rtc::Thread * network_thread,rtc::Thread * worker_thread)76 PeerConnectionTestWrapper::PeerConnectionTestWrapper(
77 const std::string& name,
78 rtc::SocketServer* socket_server,
79 rtc::Thread* network_thread,
80 rtc::Thread* worker_thread)
81 : name_(name),
82 socket_server_(socket_server),
83 network_thread_(network_thread),
84 worker_thread_(worker_thread),
85 pending_negotiation_(false) {
86 pc_thread_checker_.Detach();
87 }
88
~PeerConnectionTestWrapper()89 PeerConnectionTestWrapper::~PeerConnectionTestWrapper() {
90 RTC_DCHECK_RUN_ON(&pc_thread_checker_);
91 // Either network_thread or worker_thread might be active at this point.
92 // Relying on ~PeerConnection to properly wait for them doesn't work,
93 // as a vptr race might occur (before we enter the destruction body).
94 // See: bugs.webrtc.org/9847
95 if (pc()) {
96 pc()->Close();
97 }
98 }
99
CreatePc(const webrtc::PeerConnectionInterface::RTCConfiguration & config,rtc::scoped_refptr<webrtc::AudioEncoderFactory> audio_encoder_factory,rtc::scoped_refptr<webrtc::AudioDecoderFactory> audio_decoder_factory)100 bool PeerConnectionTestWrapper::CreatePc(
101 const webrtc::PeerConnectionInterface::RTCConfiguration& config,
102 rtc::scoped_refptr<webrtc::AudioEncoderFactory> audio_encoder_factory,
103 rtc::scoped_refptr<webrtc::AudioDecoderFactory> audio_decoder_factory) {
104 std::unique_ptr<cricket::PortAllocator> port_allocator(
105 new cricket::FakePortAllocator(
106 network_thread_,
107 std::make_unique<rtc::BasicPacketSocketFactory>(socket_server_)));
108
109 RTC_DCHECK_RUN_ON(&pc_thread_checker_);
110
111 fake_audio_capture_module_ = FakeAudioCaptureModule::Create();
112 if (fake_audio_capture_module_ == nullptr) {
113 return false;
114 }
115
116 peer_connection_factory_ = webrtc::CreatePeerConnectionFactory(
117 network_thread_, worker_thread_, rtc::Thread::Current(),
118 rtc::scoped_refptr<webrtc::AudioDeviceModule>(fake_audio_capture_module_),
119 audio_encoder_factory, audio_decoder_factory,
120 webrtc::CreateBuiltinVideoEncoderFactory(),
121 webrtc::CreateBuiltinVideoDecoderFactory(), nullptr /* audio_mixer */,
122 nullptr /* audio_processing */);
123 if (!peer_connection_factory_) {
124 return false;
125 }
126
127 std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_generator(
128 new FakeRTCCertificateGenerator());
129 webrtc::PeerConnectionDependencies deps(this);
130 deps.allocator = std::move(port_allocator);
131 deps.cert_generator = std::move(cert_generator);
132 auto result = peer_connection_factory_->CreatePeerConnectionOrError(
133 config, std::move(deps));
134 if (result.ok()) {
135 peer_connection_ = result.MoveValue();
136 return true;
137 } else {
138 return false;
139 }
140 }
141
142 rtc::scoped_refptr<webrtc::DataChannelInterface>
CreateDataChannel(const std::string & label,const webrtc::DataChannelInit & init)143 PeerConnectionTestWrapper::CreateDataChannel(
144 const std::string& label,
145 const webrtc::DataChannelInit& init) {
146 auto result = peer_connection_->CreateDataChannelOrError(label, &init);
147 if (!result.ok()) {
148 RTC_LOG(LS_ERROR) << "CreateDataChannel failed: "
149 << ToString(result.error().type()) << " "
150 << result.error().message();
151 return nullptr;
152 }
153 return result.MoveValue();
154 }
155
WaitForNegotiation()156 void PeerConnectionTestWrapper::WaitForNegotiation() {
157 EXPECT_TRUE_WAIT(!pending_negotiation_, kMaxWait);
158 }
159
OnSignalingChange(webrtc::PeerConnectionInterface::SignalingState new_state)160 void PeerConnectionTestWrapper::OnSignalingChange(
161 webrtc::PeerConnectionInterface::SignalingState new_state) {
162 if (new_state == webrtc::PeerConnectionInterface::SignalingState::kStable) {
163 pending_negotiation_ = false;
164 }
165 }
166
OnAddTrack(rtc::scoped_refptr<RtpReceiverInterface> receiver,const std::vector<rtc::scoped_refptr<MediaStreamInterface>> & streams)167 void PeerConnectionTestWrapper::OnAddTrack(
168 rtc::scoped_refptr<RtpReceiverInterface> receiver,
169 const std::vector<rtc::scoped_refptr<MediaStreamInterface>>& streams) {
170 RTC_LOG(LS_INFO) << "PeerConnectionTestWrapper " << name_ << ": OnAddTrack";
171 if (receiver->track()->kind() == MediaStreamTrackInterface::kVideoKind) {
172 auto* video_track =
173 static_cast<VideoTrackInterface*>(receiver->track().get());
174 renderer_ = std::make_unique<FakeVideoTrackRenderer>(video_track);
175 }
176 }
177
OnIceCandidate(const IceCandidateInterface * candidate)178 void PeerConnectionTestWrapper::OnIceCandidate(
179 const IceCandidateInterface* candidate) {
180 std::string sdp;
181 EXPECT_TRUE(candidate->ToString(&sdp));
182 SignalOnIceCandidateReady(candidate->sdp_mid(), candidate->sdp_mline_index(),
183 sdp);
184 }
185
OnDataChannel(rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel)186 void PeerConnectionTestWrapper::OnDataChannel(
187 rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel) {
188 SignalOnDataChannel(data_channel.get());
189 }
190
OnSuccess(SessionDescriptionInterface * desc)191 void PeerConnectionTestWrapper::OnSuccess(SessionDescriptionInterface* desc) {
192 // This callback should take the ownership of `desc`.
193 std::unique_ptr<SessionDescriptionInterface> owned_desc(desc);
194 std::string sdp;
195 EXPECT_TRUE(desc->ToString(&sdp));
196
197 RTC_LOG(LS_INFO) << "PeerConnectionTestWrapper " << name_ << ": "
198 << webrtc::SdpTypeToString(desc->GetType())
199 << " sdp created: " << sdp;
200
201 SetLocalDescription(desc->GetType(), sdp);
202
203 SignalOnSdpReady(sdp);
204 }
205
CreateOffer(const webrtc::PeerConnectionInterface::RTCOfferAnswerOptions & options)206 void PeerConnectionTestWrapper::CreateOffer(
207 const webrtc::PeerConnectionInterface::RTCOfferAnswerOptions& options) {
208 RTC_LOG(LS_INFO) << "PeerConnectionTestWrapper " << name_ << ": CreateOffer.";
209 pending_negotiation_ = true;
210 peer_connection_->CreateOffer(this, options);
211 }
212
CreateAnswer(const webrtc::PeerConnectionInterface::RTCOfferAnswerOptions & options)213 void PeerConnectionTestWrapper::CreateAnswer(
214 const webrtc::PeerConnectionInterface::RTCOfferAnswerOptions& options) {
215 RTC_LOG(LS_INFO) << "PeerConnectionTestWrapper " << name_
216 << ": CreateAnswer.";
217 pending_negotiation_ = true;
218 peer_connection_->CreateAnswer(this, options);
219 }
220
ReceiveOfferSdp(const std::string & sdp)221 void PeerConnectionTestWrapper::ReceiveOfferSdp(const std::string& sdp) {
222 SetRemoteDescription(SdpType::kOffer, sdp);
223 CreateAnswer(webrtc::PeerConnectionInterface::RTCOfferAnswerOptions());
224 }
225
ReceiveAnswerSdp(const std::string & sdp)226 void PeerConnectionTestWrapper::ReceiveAnswerSdp(const std::string& sdp) {
227 SetRemoteDescription(SdpType::kAnswer, sdp);
228 }
229
SetLocalDescription(SdpType type,const std::string & sdp)230 void PeerConnectionTestWrapper::SetLocalDescription(SdpType type,
231 const std::string& sdp) {
232 RTC_LOG(LS_INFO) << "PeerConnectionTestWrapper " << name_
233 << ": SetLocalDescription " << webrtc::SdpTypeToString(type)
234 << " " << sdp;
235
236 auto observer = rtc::make_ref_counted<MockSetSessionDescriptionObserver>();
237 peer_connection_->SetLocalDescription(
238 observer.get(), webrtc::CreateSessionDescription(type, sdp).release());
239 }
240
SetRemoteDescription(SdpType type,const std::string & sdp)241 void PeerConnectionTestWrapper::SetRemoteDescription(SdpType type,
242 const std::string& sdp) {
243 RTC_LOG(LS_INFO) << "PeerConnectionTestWrapper " << name_
244 << ": SetRemoteDescription " << webrtc::SdpTypeToString(type)
245 << " " << sdp;
246
247 auto observer = rtc::make_ref_counted<MockSetSessionDescriptionObserver>();
248 peer_connection_->SetRemoteDescription(
249 observer.get(), webrtc::CreateSessionDescription(type, sdp).release());
250 }
251
AddIceCandidate(const std::string & sdp_mid,int sdp_mline_index,const std::string & candidate)252 void PeerConnectionTestWrapper::AddIceCandidate(const std::string& sdp_mid,
253 int sdp_mline_index,
254 const std::string& candidate) {
255 std::unique_ptr<webrtc::IceCandidateInterface> owned_candidate(
256 webrtc::CreateIceCandidate(sdp_mid, sdp_mline_index, candidate, NULL));
257 EXPECT_TRUE(peer_connection_->AddIceCandidate(owned_candidate.get()));
258 }
259
WaitForCallEstablished()260 void PeerConnectionTestWrapper::WaitForCallEstablished() {
261 WaitForConnection();
262 WaitForAudio();
263 WaitForVideo();
264 }
265
WaitForConnection()266 void PeerConnectionTestWrapper::WaitForConnection() {
267 EXPECT_TRUE_WAIT(CheckForConnection(), kMaxWait);
268 RTC_LOG(LS_INFO) << "PeerConnectionTestWrapper " << name_ << ": Connected.";
269 }
270
CheckForConnection()271 bool PeerConnectionTestWrapper::CheckForConnection() {
272 return (peer_connection_->ice_connection_state() ==
273 PeerConnectionInterface::kIceConnectionConnected) ||
274 (peer_connection_->ice_connection_state() ==
275 PeerConnectionInterface::kIceConnectionCompleted);
276 }
277
WaitForAudio()278 void PeerConnectionTestWrapper::WaitForAudio() {
279 EXPECT_TRUE_WAIT(CheckForAudio(), kMaxWait);
280 RTC_LOG(LS_INFO) << "PeerConnectionTestWrapper " << name_
281 << ": Got enough audio frames.";
282 }
283
CheckForAudio()284 bool PeerConnectionTestWrapper::CheckForAudio() {
285 return (fake_audio_capture_module_->frames_received() >=
286 kTestAudioFrameCount);
287 }
288
WaitForVideo()289 void PeerConnectionTestWrapper::WaitForVideo() {
290 EXPECT_TRUE_WAIT(CheckForVideo(), kMaxWait);
291 RTC_LOG(LS_INFO) << "PeerConnectionTestWrapper " << name_
292 << ": Got enough video frames.";
293 }
294
CheckForVideo()295 bool PeerConnectionTestWrapper::CheckForVideo() {
296 if (!renderer_) {
297 return false;
298 }
299 return (renderer_->num_rendered_frames() >= kTestVideoFrameCount);
300 }
301
GetAndAddUserMedia(bool audio,const cricket::AudioOptions & audio_options,bool video)302 void PeerConnectionTestWrapper::GetAndAddUserMedia(
303 bool audio,
304 const cricket::AudioOptions& audio_options,
305 bool video) {
306 rtc::scoped_refptr<webrtc::MediaStreamInterface> stream =
307 GetUserMedia(audio, audio_options, video);
308 for (const auto& audio_track : stream->GetAudioTracks()) {
309 EXPECT_TRUE(peer_connection_->AddTrack(audio_track, {stream->id()}).ok());
310 }
311 for (const auto& video_track : stream->GetVideoTracks()) {
312 EXPECT_TRUE(peer_connection_->AddTrack(video_track, {stream->id()}).ok());
313 }
314 }
315
316 rtc::scoped_refptr<webrtc::MediaStreamInterface>
GetUserMedia(bool audio,const cricket::AudioOptions & audio_options,bool video)317 PeerConnectionTestWrapper::GetUserMedia(
318 bool audio,
319 const cricket::AudioOptions& audio_options,
320 bool video) {
321 std::string stream_id =
322 kStreamIdBase + rtc::ToString(num_get_user_media_calls_++);
323 rtc::scoped_refptr<webrtc::MediaStreamInterface> stream =
324 peer_connection_factory_->CreateLocalMediaStream(stream_id);
325
326 if (audio) {
327 cricket::AudioOptions options = audio_options;
328 // Disable highpass filter so that we can get all the test audio frames.
329 options.highpass_filter = false;
330 rtc::scoped_refptr<webrtc::AudioSourceInterface> source =
331 peer_connection_factory_->CreateAudioSource(options);
332 rtc::scoped_refptr<webrtc::AudioTrackInterface> audio_track(
333 peer_connection_factory_->CreateAudioTrack(kAudioTrackLabelBase,
334 source.get()));
335 stream->AddTrack(audio_track);
336 }
337
338 if (video) {
339 // Set max frame rate to 10fps to reduce the risk of the tests to be flaky.
340 webrtc::FakePeriodicVideoSource::Config config;
341 config.frame_interval_ms = 100;
342 config.timestamp_offset_ms = rtc::TimeMillis();
343
344 auto source = rtc::make_ref_counted<webrtc::FakePeriodicVideoTrackSource>(
345 config, /* remote */ false);
346
347 std::string videotrack_label = stream_id + kVideoTrackLabelBase;
348 rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track(
349 peer_connection_factory_->CreateVideoTrack(videotrack_label,
350 source.get()));
351
352 stream->AddTrack(video_track);
353 }
354 return stream;
355 }
356