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