/* * Copyright 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef PC_TEST_FAKE_PEER_CONNECTION_FOR_STATS_H_ #define PC_TEST_FAKE_PEER_CONNECTION_FOR_STATS_H_ #include #include #include #include #include #include #include #include "absl/strings/string_view.h" #include "api/audio/audio_device.h" #include "api/audio_options.h" #include "api/crypto/crypto_options.h" #include "api/environment/environment_factory.h" #include "api/make_ref_counted.h" #include "api/media_types.h" #include "api/peer_connection_interface.h" #include "api/rtp_receiver_interface.h" #include "api/rtp_sender_interface.h" #include "api/scoped_refptr.h" #include "api/sequence_checker.h" #include "api/task_queue/task_queue_base.h" #include "call/call.h" #include "call/payload_type_picker.h" #include "media/base/fake_media_engine.h" #include "media/base/media_channel.h" #include "p2p/base/p2p_constants.h" #include "p2p/base/port.h" #include "pc/channel.h" #include "pc/connection_context.h" #include "pc/data_channel_utils.h" #include "pc/rtp_receiver.h" #include "pc/rtp_receiver_proxy.h" #include "pc/rtp_sender.h" #include "pc/rtp_sender_proxy.h" #include "pc/rtp_transceiver.h" #include "pc/sctp_data_channel.h" #include "pc/stream_collection.h" #include "pc/test/enable_fake_media.h" #include "pc/test/fake_codec_lookup_helper.h" #include "pc/test/fake_data_channel_controller.h" #include "pc/test/fake_peer_connection_base.h" #include "pc/transport_stats.h" #include "rtc_base/checks.h" #include "rtc_base/rtc_certificate.h" #include "rtc_base/ssl_certificate.h" #include "rtc_base/thread.h" #include "rtc_base/unique_id_generator.h" namespace webrtc { // Fake VoiceMediaChannel where the result of GetStats can be configured. class FakeVoiceMediaSendChannelForStats : public FakeVoiceMediaSendChannel { public: explicit FakeVoiceMediaSendChannelForStats(TaskQueueBase* network_thread) : FakeVoiceMediaSendChannel(AudioOptions(), network_thread) {} void SetStats(const VoiceMediaInfo& voice_info) { send_stats_ = VoiceMediaSendInfo(); send_stats_->senders = voice_info.senders; send_stats_->send_codecs = voice_info.send_codecs; } // VoiceMediaChannel overrides. bool GetStats(VoiceMediaSendInfo* info) override { if (send_stats_) { *info = *send_stats_; return true; } return false; } private: std::optional send_stats_; }; class FakeVoiceMediaReceiveChannelForStats : public FakeVoiceMediaReceiveChannel { public: explicit FakeVoiceMediaReceiveChannelForStats(TaskQueueBase* network_thread) : FakeVoiceMediaReceiveChannel(AudioOptions(), network_thread) {} void SetStats(const VoiceMediaInfo& voice_info) { receive_stats_ = VoiceMediaReceiveInfo(); receive_stats_->receivers = voice_info.receivers; receive_stats_->receive_codecs = voice_info.receive_codecs; receive_stats_->device_underrun_count = voice_info.device_underrun_count; } // VoiceMediaChannel overrides. bool GetStats(VoiceMediaReceiveInfo* info, bool get_and_clear_legacy_stats) override { if (receive_stats_) { *info = *receive_stats_; return true; } return false; } private: std::optional receive_stats_; }; // Fake VideoMediaChannel where the result of GetStats can be configured. class FakeVideoMediaSendChannelForStats : public FakeVideoMediaSendChannel { public: explicit FakeVideoMediaSendChannelForStats(TaskQueueBase* network_thread) : FakeVideoMediaSendChannel(VideoOptions(), network_thread) {} void SetStats(const VideoMediaInfo& video_info) { send_stats_ = VideoMediaSendInfo(); send_stats_->senders = video_info.senders; send_stats_->aggregated_senders = video_info.aggregated_senders; send_stats_->send_codecs = video_info.send_codecs; } // VideoMediaChannel overrides. bool GetStats(VideoMediaSendInfo* info) override { if (send_stats_) { *info = *send_stats_; return true; } return false; } private: std::optional send_stats_; }; class FakeVideoMediaReceiveChannelForStats : public FakeVideoMediaReceiveChannel { public: explicit FakeVideoMediaReceiveChannelForStats(TaskQueueBase* network_thread) : FakeVideoMediaReceiveChannel(VideoOptions(), network_thread) {} void SetStats(const VideoMediaInfo& video_info) { receive_stats_ = VideoMediaReceiveInfo(); receive_stats_->receivers = video_info.receivers; receive_stats_->receive_codecs = video_info.receive_codecs; } // VideoMediaChannel overrides. bool GetStats(VideoMediaReceiveInfo* info) override { if (receive_stats_) { *info = *receive_stats_; return true; } return false; } private: std::optional receive_stats_; }; constexpr bool kDefaultRtcpMuxRequired = true; constexpr bool kDefaultSrtpRequired = true; class VoiceChannelForTesting : public VoiceChannel { public: VoiceChannelForTesting( Thread* worker_thread, Thread* network_thread, Thread* signaling_thread, std::unique_ptr send_channel, std::unique_ptr receive_channel, const std::string& content_name, bool srtp_required, CryptoOptions crypto_options, UniqueRandomIdGenerator* ssrc_generator, std::string transport_name) : VoiceChannel(worker_thread, network_thread, signaling_thread, std::move(send_channel), std::move(receive_channel), content_name, srtp_required, std::move(crypto_options), ssrc_generator), test_transport_name_(std::move(transport_name)) {} private: absl::string_view transport_name() const override { return test_transport_name_; } const std::string test_transport_name_; }; class VideoChannelForTesting : public VideoChannel { public: VideoChannelForTesting( Thread* worker_thread, Thread* network_thread, Thread* signaling_thread, std::unique_ptr send_channel, std::unique_ptr receive_channel, const std::string& content_name, bool srtp_required, CryptoOptions crypto_options, UniqueRandomIdGenerator* ssrc_generator, std::string transport_name) : VideoChannel(worker_thread, network_thread, signaling_thread, std::move(send_channel), std::move(receive_channel), content_name, srtp_required, std::move(crypto_options), ssrc_generator), test_transport_name_(std::move(transport_name)) {} private: absl::string_view transport_name() const override { return test_transport_name_; } const std::string test_transport_name_; }; // This class is intended to be fed into the StatsCollector and // RTCStatsCollector so that the stats functionality can be unit tested. // Individual tests can configure this fake as needed to simulate scenarios // under which to test the stats collectors. class FakePeerConnectionForStats : public FakePeerConnectionBase { public: // TODO(steveanton): Add support for specifying separate threads to test // multi-threading correctness. FakePeerConnectionForStats() : network_thread_(Thread::Current()), worker_thread_(Thread::Current()), signaling_thread_(Thread::Current()), // TODO(hta): remove separate thread variables and use context. dependencies_(MakeDependencies()), context_( ConnectionContext::Create(CreateEnvironment(), &dependencies_)), local_streams_(StreamCollection::Create()), remote_streams_(StreamCollection::Create()), data_channel_controller_(network_thread_), codec_lookup_helper_(context_.get()) {} ~FakePeerConnectionForStats() { for (auto transceiver : transceivers_) { transceiver->internal()->ClearChannel(); } } static PeerConnectionFactoryDependencies MakeDependencies() { PeerConnectionFactoryDependencies dependencies; dependencies.network_thread = Thread::Current(); dependencies.worker_thread = Thread::Current(); dependencies.signaling_thread = Thread::Current(); EnableFakeMedia(dependencies); return dependencies; } scoped_refptr mutable_local_streams() { return local_streams_; } scoped_refptr mutable_remote_streams() { return remote_streams_; } scoped_refptr AddSender( scoped_refptr sender) { // TODO(steveanton): Switch tests to use RtpTransceivers directly. auto sender_proxy = RtpSenderProxyWithInternal::Create( signaling_thread_, sender); GetOrCreateFirstTransceiverOfType(sender->media_type()) ->internal() ->AddSender(sender_proxy); return sender_proxy; } void RemoveSender(scoped_refptr sender) { GetOrCreateFirstTransceiverOfType(sender->media_type()) ->internal() ->RemoveSender(sender.get()); } scoped_refptr AddReceiver( scoped_refptr receiver) { // TODO(steveanton): Switch tests to use RtpTransceivers directly. auto receiver_proxy = RtpReceiverProxyWithInternal::Create( signaling_thread_, worker_thread_, receiver); GetOrCreateFirstTransceiverOfType(receiver->media_type()) ->internal() ->AddReceiver(receiver_proxy); return receiver_proxy; } void RemoveReceiver(scoped_refptr receiver) { GetOrCreateFirstTransceiverOfType(receiver->media_type()) ->internal() ->RemoveReceiver(receiver.get()); } std::pair AddVoiceChannel(const std::string& mid, const std::string& transport_name, VoiceMediaInfo initial_stats = VoiceMediaInfo()) { auto voice_media_send_channel = std::make_unique(network_thread_); auto voice_media_receive_channel = std::make_unique(network_thread_); auto* voice_media_send_channel_ptr = voice_media_send_channel.get(); auto* voice_media_receive_channel_ptr = voice_media_receive_channel.get(); auto voice_channel = std::make_unique( worker_thread_, network_thread_, signaling_thread_, std::move(voice_media_send_channel), std::move(voice_media_receive_channel), mid, kDefaultSrtpRequired, CryptoOptions(), context_->ssrc_generator(), transport_name); auto transceiver = GetOrCreateFirstTransceiverOfType(webrtc::MediaType::AUDIO)->internal(); if (transceiver->channel()) { // This transceiver already has a channel, create a new one. transceiver = CreateTransceiverOfType(webrtc::MediaType::AUDIO)->internal(); } RTC_DCHECK(!transceiver->channel()); transceiver->SetChannel(std::move(voice_channel), [](const std::string&) { return nullptr; }); voice_media_send_channel_ptr->SetStats(initial_stats); voice_media_receive_channel_ptr->SetStats(initial_stats); return std::make_pair(voice_media_send_channel_ptr, voice_media_receive_channel_ptr); } std::pair AddVideoChannel(const std::string& mid, const std::string& transport_name, VideoMediaInfo initial_stats = VideoMediaInfo()) { auto video_media_send_channel = std::make_unique(network_thread_); auto video_media_receive_channel = std::make_unique(network_thread_); auto video_media_send_channel_ptr = video_media_send_channel.get(); auto video_media_receive_channel_ptr = video_media_receive_channel.get(); auto video_channel = std::make_unique( worker_thread_, network_thread_, signaling_thread_, std::move(video_media_send_channel), std::move(video_media_receive_channel), mid, kDefaultSrtpRequired, CryptoOptions(), context_->ssrc_generator(), transport_name); auto transceiver = GetOrCreateFirstTransceiverOfType(webrtc::MediaType::VIDEO)->internal(); if (transceiver->channel()) { // This transceiver already has a channel, create a new one. transceiver = CreateTransceiverOfType(webrtc::MediaType::VIDEO)->internal(); } RTC_DCHECK(!transceiver->channel()); transceiver->SetChannel(std::move(video_channel), [](const std::string&) { return nullptr; }); video_media_send_channel_ptr->SetStats(initial_stats); video_media_receive_channel_ptr->SetStats(initial_stats); return std::make_pair(video_media_send_channel_ptr, video_media_receive_channel_ptr); } void AddSctpDataChannel(const std::string& label) { AddSctpDataChannel(label, InternalDataChannelInit()); } void AddSctpDataChannel(const std::string& label, const InternalDataChannelInit& init) { // TODO(bugs.webrtc.org/11547): Supply a separate network thread. AddSctpDataChannel(SctpDataChannel::Create( data_channel_controller_.weak_ptr(), label, false, init, Thread::Current(), Thread::Current())); } void AddSctpDataChannel(scoped_refptr data_channel) { sctp_data_channels_.push_back(data_channel); } void SetTransportStats(const std::string& transport_name, const TransportChannelStats& channel_stats) { SetTransportStats(transport_name, std::vector{channel_stats}); } void SetTransportStats( const std::string& transport_name, const std::vector& channel_stats_list) { TransportStats transport_stats; transport_stats.transport_name = transport_name; transport_stats.channel_stats = channel_stats_list; transport_stats_by_name_[transport_name] = transport_stats; } void SetCallStats(const Call::Stats& call_stats) { call_stats_ = call_stats; } void SetAudioDeviceStats( std::optional audio_device_stats) { audio_device_stats_ = audio_device_stats; } void SetLocalCertificate(const std::string& transport_name, scoped_refptr certificate) { local_certificates_by_transport_[transport_name] = certificate; } void SetRemoteCertChain(const std::string& transport_name, std::unique_ptr chain) { remote_cert_chains_by_transport_[transport_name] = std::move(chain); } // PeerConnectionInterface overrides. scoped_refptr local_streams() override { return local_streams_; } scoped_refptr remote_streams() override { return remote_streams_; } std::vector> GetSenders() const override { std::vector> senders; for (auto transceiver : transceivers_) { for (auto sender : transceiver->internal()->senders()) { senders.push_back(sender); } } return senders; } std::vector> GetReceivers() const override { std::vector> receivers; for (auto transceiver : transceivers_) { for (auto receiver : transceiver->internal()->receivers()) { receivers.push_back(receiver); } } return receivers; } // PeerConnectionInternal overrides. Thread* network_thread() const override { return network_thread_; } Thread* worker_thread() const override { return worker_thread_; } Thread* signaling_thread() const override { return signaling_thread_; } std::vector>> GetTransceiversInternal() const override { return transceivers_; } std::vector GetDataChannelStats() const override { RTC_DCHECK_RUN_ON(signaling_thread()); std::vector stats; for (const auto& channel : sctp_data_channels_) stats.push_back(channel->GetStats()); return stats; } CandidateStatsList GetPooledCandidateStats() const override { return {}; } std::map GetTransportStatsByNames( const std::set& transport_names) override { RTC_DCHECK_RUN_ON(network_thread_); std::map transport_stats_by_name; for (const std::string& transport_name : transport_names) { transport_stats_by_name[transport_name] = GetTransportStatsByName(transport_name); } return transport_stats_by_name; } Call::Stats GetCallStats() override { return call_stats_; } std::optional GetAudioDeviceStats() override { return audio_device_stats_; } bool GetLocalCertificate( const std::string& transport_name, scoped_refptr* certificate) override { auto it = local_certificates_by_transport_.find(transport_name); if (it != local_certificates_by_transport_.end()) { *certificate = it->second; return true; } else { return false; } } std::unique_ptr GetRemoteSSLCertChain( const std::string& transport_name) override { auto it = remote_cert_chains_by_transport_.find(transport_name); if (it != remote_cert_chains_by_transport_.end()) { return it->second->Clone(); } else { return nullptr; } } PayloadTypePicker& payload_type_picker() { return payload_type_picker_; } private: TransportStats GetTransportStatsByName(const std::string& transport_name) { auto it = transport_stats_by_name_.find(transport_name); if (it != transport_stats_by_name_.end()) { // If specific transport stats have been specified, return those. return it->second; } // Otherwise, generate some dummy stats. TransportChannelStats channel_stats; channel_stats.component = ICE_CANDIDATE_COMPONENT_RTP; TransportStats transport_stats; transport_stats.transport_name = transport_name; transport_stats.channel_stats.push_back(channel_stats); return transport_stats; } scoped_refptr> GetOrCreateFirstTransceiverOfType(webrtc::MediaType media_type) { for (auto transceiver : transceivers_) { if (transceiver->internal()->media_type() == media_type) { return transceiver; } } return CreateTransceiverOfType(media_type); } scoped_refptr> CreateTransceiverOfType(webrtc::MediaType media_type) { auto transceiver = RtpTransceiverProxyWithInternal::Create( signaling_thread_, make_ref_counted(media_type, context_.get(), &codec_lookup_helper_)); transceivers_.push_back(transceiver); return transceiver; } Thread* const network_thread_; Thread* const worker_thread_; Thread* const signaling_thread_; PeerConnectionFactoryDependencies dependencies_; scoped_refptr context_; scoped_refptr local_streams_; scoped_refptr remote_streams_; std::vector>> transceivers_; FakeDataChannelController data_channel_controller_; std::vector> sctp_data_channels_; std::map transport_stats_by_name_; Call::Stats call_stats_; std::optional audio_device_stats_; std::map> local_certificates_by_transport_; std::map> remote_cert_chains_by_transport_; PayloadTypePicker payload_type_picker_; FakeCodecLookupHelper codec_lookup_helper_; }; } // namespace webrtc #endif // PC_TEST_FAKE_PEER_CONNECTION_FOR_STATS_H_