1 /* 2 * Copyright 2018 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 #ifndef PC_TEST_FAKE_PEER_CONNECTION_FOR_STATS_H_ 12 #define PC_TEST_FAKE_PEER_CONNECTION_FOR_STATS_H_ 13 14 #include <map> 15 #include <memory> 16 #include <set> 17 #include <string> 18 #include <utility> 19 #include <vector> 20 21 #include "media/base/fake_media_engine.h" 22 #include "pc/channel.h" 23 #include "pc/stream_collection.h" 24 #include "pc/test/fake_data_channel_controller.h" 25 #include "pc/test/fake_peer_connection_base.h" 26 27 namespace webrtc { 28 29 // Fake VoiceMediaChannel where the result of GetStats can be configured. 30 class FakeVoiceMediaChannelForStats : public cricket::FakeVoiceMediaChannel { 31 public: FakeVoiceMediaChannelForStats(TaskQueueBase * network_thread)32 explicit FakeVoiceMediaChannelForStats(TaskQueueBase* network_thread) 33 : cricket::FakeVoiceMediaChannel(nullptr, 34 cricket::AudioOptions(), 35 network_thread) {} 36 SetStats(const cricket::VoiceMediaInfo & voice_info)37 void SetStats(const cricket::VoiceMediaInfo& voice_info) { 38 stats_ = voice_info; 39 } 40 41 // VoiceMediaChannel overrides. GetStats(cricket::VoiceMediaInfo * info,bool get_and_clear_legacy_stats)42 bool GetStats(cricket::VoiceMediaInfo* info, 43 bool get_and_clear_legacy_stats) override { 44 if (stats_) { 45 *info = *stats_; 46 return true; 47 } 48 return false; 49 } 50 51 private: 52 absl::optional<cricket::VoiceMediaInfo> stats_; 53 }; 54 55 // Fake VideoMediaChannel where the result of GetStats can be configured. 56 class FakeVideoMediaChannelForStats : public cricket::FakeVideoMediaChannel { 57 public: FakeVideoMediaChannelForStats(TaskQueueBase * network_thread)58 explicit FakeVideoMediaChannelForStats(TaskQueueBase* network_thread) 59 : cricket::FakeVideoMediaChannel(nullptr, 60 cricket::VideoOptions(), 61 network_thread) {} 62 SetStats(const cricket::VideoMediaInfo & video_info)63 void SetStats(const cricket::VideoMediaInfo& video_info) { 64 stats_ = video_info; 65 } 66 67 // VideoMediaChannel overrides. GetStats(cricket::VideoMediaInfo * info)68 bool GetStats(cricket::VideoMediaInfo* info) override { 69 if (stats_) { 70 *info = *stats_; 71 return true; 72 } 73 return false; 74 } 75 76 private: 77 absl::optional<cricket::VideoMediaInfo> stats_; 78 }; 79 80 constexpr bool kDefaultRtcpMuxRequired = true; 81 constexpr bool kDefaultSrtpRequired = true; 82 83 class VoiceChannelForTesting : public cricket::VoiceChannel { 84 public: VoiceChannelForTesting(rtc::Thread * worker_thread,rtc::Thread * network_thread,rtc::Thread * signaling_thread,std::unique_ptr<cricket::VoiceMediaChannel> channel,const std::string & content_name,bool srtp_required,webrtc::CryptoOptions crypto_options,rtc::UniqueRandomIdGenerator * ssrc_generator,std::string transport_name)85 VoiceChannelForTesting(rtc::Thread* worker_thread, 86 rtc::Thread* network_thread, 87 rtc::Thread* signaling_thread, 88 std::unique_ptr<cricket::VoiceMediaChannel> channel, 89 const std::string& content_name, 90 bool srtp_required, 91 webrtc::CryptoOptions crypto_options, 92 rtc::UniqueRandomIdGenerator* ssrc_generator, 93 std::string transport_name) 94 : VoiceChannel(worker_thread, 95 network_thread, 96 signaling_thread, 97 std::move(channel), 98 content_name, 99 srtp_required, 100 std::move(crypto_options), 101 ssrc_generator), 102 test_transport_name_(std::move(transport_name)) {} 103 104 private: transport_name()105 absl::string_view transport_name() const override { 106 return test_transport_name_; 107 } 108 109 const std::string test_transport_name_; 110 }; 111 112 class VideoChannelForTesting : public cricket::VideoChannel { 113 public: VideoChannelForTesting(rtc::Thread * worker_thread,rtc::Thread * network_thread,rtc::Thread * signaling_thread,std::unique_ptr<cricket::VideoMediaChannel> channel,const std::string & content_name,bool srtp_required,webrtc::CryptoOptions crypto_options,rtc::UniqueRandomIdGenerator * ssrc_generator,std::string transport_name)114 VideoChannelForTesting(rtc::Thread* worker_thread, 115 rtc::Thread* network_thread, 116 rtc::Thread* signaling_thread, 117 std::unique_ptr<cricket::VideoMediaChannel> channel, 118 const std::string& content_name, 119 bool srtp_required, 120 webrtc::CryptoOptions crypto_options, 121 rtc::UniqueRandomIdGenerator* ssrc_generator, 122 std::string transport_name) 123 : VideoChannel(worker_thread, 124 network_thread, 125 signaling_thread, 126 std::move(channel), 127 content_name, 128 srtp_required, 129 std::move(crypto_options), 130 ssrc_generator), 131 test_transport_name_(std::move(transport_name)) {} 132 133 private: transport_name()134 absl::string_view transport_name() const override { 135 return test_transport_name_; 136 } 137 138 const std::string test_transport_name_; 139 }; 140 141 // This class is intended to be fed into the StatsCollector and 142 // RTCStatsCollector so that the stats functionality can be unit tested. 143 // Individual tests can configure this fake as needed to simulate scenarios 144 // under which to test the stats collectors. 145 class FakePeerConnectionForStats : public FakePeerConnectionBase { 146 public: 147 // TODO(steveanton): Add support for specifying separate threads to test 148 // multi-threading correctness. FakePeerConnectionForStats()149 FakePeerConnectionForStats() 150 : network_thread_(rtc::Thread::Current()), 151 worker_thread_(rtc::Thread::Current()), 152 signaling_thread_(rtc::Thread::Current()), 153 // TODO(hta): remove separate thread variables and use context. 154 dependencies_(MakeDependencies()), 155 context_(ConnectionContext::Create(&dependencies_)), 156 local_streams_(StreamCollection::Create()), 157 remote_streams_(StreamCollection::Create()) {} 158 ~FakePeerConnectionForStats()159 ~FakePeerConnectionForStats() { 160 for (auto transceiver : transceivers_) { 161 transceiver->internal()->ClearChannel(); 162 } 163 } 164 MakeDependencies()165 static PeerConnectionFactoryDependencies MakeDependencies() { 166 PeerConnectionFactoryDependencies dependencies; 167 dependencies.network_thread = rtc::Thread::Current(); 168 dependencies.worker_thread = rtc::Thread::Current(); 169 dependencies.signaling_thread = rtc::Thread::Current(); 170 dependencies.media_engine = std::make_unique<cricket::FakeMediaEngine>(); 171 return dependencies; 172 } 173 mutable_local_streams()174 rtc::scoped_refptr<StreamCollection> mutable_local_streams() { 175 return local_streams_; 176 } 177 mutable_remote_streams()178 rtc::scoped_refptr<StreamCollection> mutable_remote_streams() { 179 return remote_streams_; 180 } 181 AddSender(rtc::scoped_refptr<RtpSenderInternal> sender)182 rtc::scoped_refptr<RtpSenderInterface> AddSender( 183 rtc::scoped_refptr<RtpSenderInternal> sender) { 184 // TODO(steveanton): Switch tests to use RtpTransceivers directly. 185 auto sender_proxy = RtpSenderProxyWithInternal<RtpSenderInternal>::Create( 186 signaling_thread_, sender); 187 GetOrCreateFirstTransceiverOfType(sender->media_type()) 188 ->internal() 189 ->AddSender(sender_proxy); 190 return sender_proxy; 191 } 192 RemoveSender(rtc::scoped_refptr<RtpSenderInterface> sender)193 void RemoveSender(rtc::scoped_refptr<RtpSenderInterface> sender) { 194 GetOrCreateFirstTransceiverOfType(sender->media_type()) 195 ->internal() 196 ->RemoveSender(sender.get()); 197 } 198 AddReceiver(rtc::scoped_refptr<RtpReceiverInternal> receiver)199 rtc::scoped_refptr<RtpReceiverInterface> AddReceiver( 200 rtc::scoped_refptr<RtpReceiverInternal> receiver) { 201 // TODO(steveanton): Switch tests to use RtpTransceivers directly. 202 auto receiver_proxy = 203 RtpReceiverProxyWithInternal<RtpReceiverInternal>::Create( 204 signaling_thread_, worker_thread_, receiver); 205 GetOrCreateFirstTransceiverOfType(receiver->media_type()) 206 ->internal() 207 ->AddReceiver(receiver_proxy); 208 return receiver_proxy; 209 } 210 RemoveReceiver(rtc::scoped_refptr<RtpReceiverInterface> receiver)211 void RemoveReceiver(rtc::scoped_refptr<RtpReceiverInterface> receiver) { 212 GetOrCreateFirstTransceiverOfType(receiver->media_type()) 213 ->internal() 214 ->RemoveReceiver(receiver.get()); 215 } 216 217 FakeVoiceMediaChannelForStats* AddVoiceChannel( 218 const std::string& mid, 219 const std::string& transport_name, 220 cricket::VoiceMediaInfo initial_stats = cricket::VoiceMediaInfo()) { 221 auto voice_media_channel = 222 std::make_unique<FakeVoiceMediaChannelForStats>(network_thread_); 223 auto* voice_media_channel_ptr = voice_media_channel.get(); 224 auto voice_channel = std::make_unique<VoiceChannelForTesting>( 225 worker_thread_, network_thread_, signaling_thread_, 226 std::move(voice_media_channel), mid, kDefaultSrtpRequired, 227 webrtc::CryptoOptions(), context_->ssrc_generator(), transport_name); 228 auto transceiver = 229 GetOrCreateFirstTransceiverOfType(cricket::MEDIA_TYPE_AUDIO) 230 ->internal(); 231 if (transceiver->channel()) { 232 // This transceiver already has a channel, create a new one. 233 transceiver = 234 CreateTransceiverOfType(cricket::MEDIA_TYPE_AUDIO)->internal(); 235 } 236 RTC_DCHECK(!transceiver->channel()); 237 transceiver->SetChannel(std::move(voice_channel), 238 [](const std::string&) { return nullptr; }); 239 voice_media_channel_ptr->SetStats(initial_stats); 240 return voice_media_channel_ptr; 241 } 242 243 FakeVideoMediaChannelForStats* AddVideoChannel( 244 const std::string& mid, 245 const std::string& transport_name, 246 cricket::VideoMediaInfo initial_stats = cricket::VideoMediaInfo()) { 247 auto video_media_channel = 248 std::make_unique<FakeVideoMediaChannelForStats>(network_thread_); 249 auto video_media_channel_ptr = video_media_channel.get(); 250 auto video_channel = std::make_unique<VideoChannelForTesting>( 251 worker_thread_, network_thread_, signaling_thread_, 252 std::move(video_media_channel), mid, kDefaultSrtpRequired, 253 webrtc::CryptoOptions(), context_->ssrc_generator(), transport_name); 254 auto transceiver = 255 GetOrCreateFirstTransceiverOfType(cricket::MEDIA_TYPE_VIDEO) 256 ->internal(); 257 if (transceiver->channel()) { 258 // This transceiver already has a channel, create a new one. 259 transceiver = 260 CreateTransceiverOfType(cricket::MEDIA_TYPE_VIDEO)->internal(); 261 } 262 RTC_DCHECK(!transceiver->channel()); 263 transceiver->SetChannel(std::move(video_channel), 264 [](const std::string&) { return nullptr; }); 265 video_media_channel_ptr->SetStats(initial_stats); 266 return video_media_channel_ptr; 267 } 268 AddSctpDataChannel(const std::string & label)269 void AddSctpDataChannel(const std::string& label) { 270 AddSctpDataChannel(label, InternalDataChannelInit()); 271 } 272 AddSctpDataChannel(const std::string & label,const InternalDataChannelInit & init)273 void AddSctpDataChannel(const std::string& label, 274 const InternalDataChannelInit& init) { 275 // TODO(bugs.webrtc.org/11547): Supply a separate network thread. 276 AddSctpDataChannel(SctpDataChannel::Create(&data_channel_controller_, label, 277 init, rtc::Thread::Current(), 278 rtc::Thread::Current())); 279 } 280 AddSctpDataChannel(rtc::scoped_refptr<SctpDataChannel> data_channel)281 void AddSctpDataChannel(rtc::scoped_refptr<SctpDataChannel> data_channel) { 282 sctp_data_channels_.push_back(data_channel); 283 } 284 SetTransportStats(const std::string & transport_name,const cricket::TransportChannelStats & channel_stats)285 void SetTransportStats(const std::string& transport_name, 286 const cricket::TransportChannelStats& channel_stats) { 287 SetTransportStats( 288 transport_name, 289 std::vector<cricket::TransportChannelStats>{channel_stats}); 290 } 291 SetTransportStats(const std::string & transport_name,const std::vector<cricket::TransportChannelStats> & channel_stats_list)292 void SetTransportStats( 293 const std::string& transport_name, 294 const std::vector<cricket::TransportChannelStats>& channel_stats_list) { 295 cricket::TransportStats transport_stats; 296 transport_stats.transport_name = transport_name; 297 transport_stats.channel_stats = channel_stats_list; 298 transport_stats_by_name_[transport_name] = transport_stats; 299 } 300 SetCallStats(const Call::Stats & call_stats)301 void SetCallStats(const Call::Stats& call_stats) { call_stats_ = call_stats; } 302 SetLocalCertificate(const std::string & transport_name,rtc::scoped_refptr<rtc::RTCCertificate> certificate)303 void SetLocalCertificate( 304 const std::string& transport_name, 305 rtc::scoped_refptr<rtc::RTCCertificate> certificate) { 306 local_certificates_by_transport_[transport_name] = certificate; 307 } 308 SetRemoteCertChain(const std::string & transport_name,std::unique_ptr<rtc::SSLCertChain> chain)309 void SetRemoteCertChain(const std::string& transport_name, 310 std::unique_ptr<rtc::SSLCertChain> chain) { 311 remote_cert_chains_by_transport_[transport_name] = std::move(chain); 312 } 313 314 // PeerConnectionInterface overrides. 315 local_streams()316 rtc::scoped_refptr<StreamCollectionInterface> local_streams() override { 317 return local_streams_; 318 } 319 remote_streams()320 rtc::scoped_refptr<StreamCollectionInterface> remote_streams() override { 321 return remote_streams_; 322 } 323 GetSenders()324 std::vector<rtc::scoped_refptr<RtpSenderInterface>> GetSenders() 325 const override { 326 std::vector<rtc::scoped_refptr<RtpSenderInterface>> senders; 327 for (auto transceiver : transceivers_) { 328 for (auto sender : transceiver->internal()->senders()) { 329 senders.push_back(sender); 330 } 331 } 332 return senders; 333 } 334 GetReceivers()335 std::vector<rtc::scoped_refptr<RtpReceiverInterface>> GetReceivers() 336 const override { 337 std::vector<rtc::scoped_refptr<RtpReceiverInterface>> receivers; 338 for (auto transceiver : transceivers_) { 339 for (auto receiver : transceiver->internal()->receivers()) { 340 receivers.push_back(receiver); 341 } 342 } 343 return receivers; 344 } 345 346 // PeerConnectionInternal overrides. 347 network_thread()348 rtc::Thread* network_thread() const override { return network_thread_; } 349 worker_thread()350 rtc::Thread* worker_thread() const override { return worker_thread_; } 351 signaling_thread()352 rtc::Thread* signaling_thread() const override { return signaling_thread_; } 353 354 std::vector< 355 rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>> GetTransceiversInternal()356 GetTransceiversInternal() const override { 357 return transceivers_; 358 } 359 GetDataChannelStats()360 std::vector<DataChannelStats> GetDataChannelStats() const override { 361 RTC_DCHECK_RUN_ON(signaling_thread()); 362 std::vector<DataChannelStats> stats; 363 for (const auto& channel : sctp_data_channels_) 364 stats.push_back(channel->GetStats()); 365 return stats; 366 } 367 GetPooledCandidateStats()368 cricket::CandidateStatsList GetPooledCandidateStats() const override { 369 return {}; 370 } 371 GetTransportStatsByNames(const std::set<std::string> & transport_names)372 std::map<std::string, cricket::TransportStats> GetTransportStatsByNames( 373 const std::set<std::string>& transport_names) override { 374 RTC_DCHECK_RUN_ON(network_thread_); 375 std::map<std::string, cricket::TransportStats> transport_stats_by_name; 376 for (const std::string& transport_name : transport_names) { 377 transport_stats_by_name[transport_name] = 378 GetTransportStatsByName(transport_name); 379 } 380 return transport_stats_by_name; 381 } 382 GetCallStats()383 Call::Stats GetCallStats() override { return call_stats_; } 384 GetLocalCertificate(const std::string & transport_name,rtc::scoped_refptr<rtc::RTCCertificate> * certificate)385 bool GetLocalCertificate( 386 const std::string& transport_name, 387 rtc::scoped_refptr<rtc::RTCCertificate>* certificate) override { 388 auto it = local_certificates_by_transport_.find(transport_name); 389 if (it != local_certificates_by_transport_.end()) { 390 *certificate = it->second; 391 return true; 392 } else { 393 return false; 394 } 395 } 396 GetRemoteSSLCertChain(const std::string & transport_name)397 std::unique_ptr<rtc::SSLCertChain> GetRemoteSSLCertChain( 398 const std::string& transport_name) override { 399 auto it = remote_cert_chains_by_transport_.find(transport_name); 400 if (it != remote_cert_chains_by_transport_.end()) { 401 return it->second->Clone(); 402 } else { 403 return nullptr; 404 } 405 } 406 407 private: GetTransportStatsByName(const std::string & transport_name)408 cricket::TransportStats GetTransportStatsByName( 409 const std::string& transport_name) { 410 auto it = transport_stats_by_name_.find(transport_name); 411 if (it != transport_stats_by_name_.end()) { 412 // If specific transport stats have been specified, return those. 413 return it->second; 414 } 415 // Otherwise, generate some dummy stats. 416 cricket::TransportChannelStats channel_stats; 417 channel_stats.component = cricket::ICE_CANDIDATE_COMPONENT_RTP; 418 cricket::TransportStats transport_stats; 419 transport_stats.transport_name = transport_name; 420 transport_stats.channel_stats.push_back(channel_stats); 421 return transport_stats; 422 } 423 424 rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>> GetOrCreateFirstTransceiverOfType(cricket::MediaType media_type)425 GetOrCreateFirstTransceiverOfType(cricket::MediaType media_type) { 426 for (auto transceiver : transceivers_) { 427 if (transceiver->internal()->media_type() == media_type) { 428 return transceiver; 429 } 430 } 431 return CreateTransceiverOfType(media_type); 432 } 433 434 rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>> CreateTransceiverOfType(cricket::MediaType media_type)435 CreateTransceiverOfType(cricket::MediaType media_type) { 436 auto transceiver = RtpTransceiverProxyWithInternal<RtpTransceiver>::Create( 437 signaling_thread_, 438 rtc::make_ref_counted<RtpTransceiver>(media_type, context_.get())); 439 transceivers_.push_back(transceiver); 440 return transceiver; 441 } 442 443 rtc::Thread* const network_thread_; 444 rtc::Thread* const worker_thread_; 445 rtc::Thread* const signaling_thread_; 446 447 PeerConnectionFactoryDependencies dependencies_; 448 rtc::scoped_refptr<ConnectionContext> context_; 449 450 rtc::scoped_refptr<StreamCollection> local_streams_; 451 rtc::scoped_refptr<StreamCollection> remote_streams_; 452 453 std::vector< 454 rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>> 455 transceivers_; 456 457 FakeDataChannelController data_channel_controller_; 458 459 std::vector<rtc::scoped_refptr<SctpDataChannel>> sctp_data_channels_; 460 461 std::map<std::string, cricket::TransportStats> transport_stats_by_name_; 462 463 Call::Stats call_stats_; 464 465 std::map<std::string, rtc::scoped_refptr<rtc::RTCCertificate>> 466 local_certificates_by_transport_; 467 std::map<std::string, std::unique_ptr<rtc::SSLCertChain>> 468 remote_cert_chains_by_transport_; 469 }; 470 471 } // namespace webrtc 472 473 #endif // PC_TEST_FAKE_PEER_CONNECTION_FOR_STATS_H_ 474