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