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