|  | /* | 
|  | *  Copyright (c) 2013 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. | 
|  | */ | 
|  |  | 
|  | #include "call/call.h" | 
|  |  | 
|  | #include <string.h> | 
|  |  | 
|  | #include <algorithm> | 
|  | #include <atomic> | 
|  | #include <cstdint> | 
|  | #include <map> | 
|  | #include <memory> | 
|  | #include <set> | 
|  | #include <utility> | 
|  | #include <vector> | 
|  |  | 
|  | #include "absl/functional/bind_front.h" | 
|  | #include "absl/strings/string_view.h" | 
|  | #include "absl/types/optional.h" | 
|  | #include "api/media_types.h" | 
|  | #include "api/rtc_event_log/rtc_event_log.h" | 
|  | #include "api/sequence_checker.h" | 
|  | #include "api/task_queue/pending_task_safety_flag.h" | 
|  | #include "api/transport/network_control.h" | 
|  | #include "audio/audio_receive_stream.h" | 
|  | #include "audio/audio_send_stream.h" | 
|  | #include "audio/audio_state.h" | 
|  | #include "call/adaptation/broadcast_resource_listener.h" | 
|  | #include "call/bitrate_allocator.h" | 
|  | #include "call/flexfec_receive_stream_impl.h" | 
|  | #include "call/packet_receiver.h" | 
|  | #include "call/receive_time_calculator.h" | 
|  | #include "call/rtp_stream_receiver_controller.h" | 
|  | #include "call/rtp_transport_controller_send.h" | 
|  | #include "call/rtp_transport_controller_send_factory.h" | 
|  | #include "call/version.h" | 
|  | #include "logging/rtc_event_log/events/rtc_event_audio_receive_stream_config.h" | 
|  | #include "logging/rtc_event_log/events/rtc_event_rtcp_packet_incoming.h" | 
|  | #include "logging/rtc_event_log/events/rtc_event_rtp_packet_incoming.h" | 
|  | #include "logging/rtc_event_log/events/rtc_event_video_receive_stream_config.h" | 
|  | #include "logging/rtc_event_log/events/rtc_event_video_send_stream_config.h" | 
|  | #include "logging/rtc_event_log/rtc_stream_config.h" | 
|  | #include "modules/congestion_controller/include/receive_side_congestion_controller.h" | 
|  | #include "modules/rtp_rtcp/include/flexfec_receiver.h" | 
|  | #include "modules/rtp_rtcp/include/rtp_header_extension_map.h" | 
|  | #include "modules/rtp_rtcp/source/byte_io.h" | 
|  | #include "modules/rtp_rtcp/source/rtp_header_extensions.h" | 
|  | #include "modules/rtp_rtcp/source/rtp_packet_received.h" | 
|  | #include "modules/rtp_rtcp/source/rtp_util.h" | 
|  | #include "modules/video_coding/fec_controller_default.h" | 
|  | #include "rtc_base/checks.h" | 
|  | #include "rtc_base/logging.h" | 
|  | #include "rtc_base/strings/string_builder.h" | 
|  | #include "rtc_base/system/no_unique_address.h" | 
|  | #include "rtc_base/task_utils/repeating_task.h" | 
|  | #include "rtc_base/thread_annotations.h" | 
|  | #include "rtc_base/time_utils.h" | 
|  | #include "rtc_base/trace_event.h" | 
|  | #include "system_wrappers/include/clock.h" | 
|  | #include "system_wrappers/include/cpu_info.h" | 
|  | #include "system_wrappers/include/metrics.h" | 
|  | #include "video/call_stats2.h" | 
|  | #include "video/send_delay_stats.h" | 
|  | #include "video/stats_counter.h" | 
|  | #include "video/video_receive_stream2.h" | 
|  | #include "video/video_send_stream.h" | 
|  |  | 
|  | namespace webrtc { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | const int* FindKeyByValue(const std::map<int, int>& m, int v) { | 
|  | for (const auto& kv : m) { | 
|  | if (kv.second == v) | 
|  | return &kv.first; | 
|  | } | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<rtclog::StreamConfig> CreateRtcLogStreamConfig( | 
|  | const VideoReceiveStreamInterface::Config& config) { | 
|  | auto rtclog_config = std::make_unique<rtclog::StreamConfig>(); | 
|  | rtclog_config->remote_ssrc = config.rtp.remote_ssrc; | 
|  | rtclog_config->local_ssrc = config.rtp.local_ssrc; | 
|  | rtclog_config->rtx_ssrc = config.rtp.rtx_ssrc; | 
|  | rtclog_config->rtcp_mode = config.rtp.rtcp_mode; | 
|  |  | 
|  | for (const auto& d : config.decoders) { | 
|  | const int* search = | 
|  | FindKeyByValue(config.rtp.rtx_associated_payload_types, d.payload_type); | 
|  | rtclog_config->codecs.emplace_back(d.video_format.name, d.payload_type, | 
|  | search ? *search : 0); | 
|  | } | 
|  | return rtclog_config; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<rtclog::StreamConfig> CreateRtcLogStreamConfig( | 
|  | const VideoSendStream::Config& config, | 
|  | size_t ssrc_index) { | 
|  | auto rtclog_config = std::make_unique<rtclog::StreamConfig>(); | 
|  | rtclog_config->local_ssrc = config.rtp.ssrcs[ssrc_index]; | 
|  | if (ssrc_index < config.rtp.rtx.ssrcs.size()) { | 
|  | rtclog_config->rtx_ssrc = config.rtp.rtx.ssrcs[ssrc_index]; | 
|  | } | 
|  | rtclog_config->rtcp_mode = config.rtp.rtcp_mode; | 
|  | rtclog_config->rtp_extensions = config.rtp.extensions; | 
|  |  | 
|  | rtclog_config->codecs.emplace_back(config.rtp.payload_name, | 
|  | config.rtp.payload_type, | 
|  | config.rtp.rtx.payload_type); | 
|  | return rtclog_config; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<rtclog::StreamConfig> CreateRtcLogStreamConfig( | 
|  | const AudioReceiveStreamInterface::Config& config) { | 
|  | auto rtclog_config = std::make_unique<rtclog::StreamConfig>(); | 
|  | rtclog_config->remote_ssrc = config.rtp.remote_ssrc; | 
|  | rtclog_config->local_ssrc = config.rtp.local_ssrc; | 
|  | return rtclog_config; | 
|  | } | 
|  |  | 
|  | TaskQueueBase* GetCurrentTaskQueueOrThread() { | 
|  | TaskQueueBase* current = TaskQueueBase::Current(); | 
|  | if (!current) | 
|  | current = rtc::ThreadManager::Instance()->CurrentThread(); | 
|  | return current; | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | namespace internal { | 
|  |  | 
|  | // Wraps an injected resource in a BroadcastResourceListener and handles adding | 
|  | // and removing adapter resources to individual VideoSendStreams. | 
|  | class ResourceVideoSendStreamForwarder { | 
|  | public: | 
|  | ResourceVideoSendStreamForwarder( | 
|  | rtc::scoped_refptr<webrtc::Resource> resource) | 
|  | : broadcast_resource_listener_(resource) { | 
|  | broadcast_resource_listener_.StartListening(); | 
|  | } | 
|  | ~ResourceVideoSendStreamForwarder() { | 
|  | RTC_DCHECK(adapter_resources_.empty()); | 
|  | broadcast_resource_listener_.StopListening(); | 
|  | } | 
|  |  | 
|  | rtc::scoped_refptr<webrtc::Resource> Resource() const { | 
|  | return broadcast_resource_listener_.SourceResource(); | 
|  | } | 
|  |  | 
|  | void OnCreateVideoSendStream(VideoSendStream* video_send_stream) { | 
|  | RTC_DCHECK(adapter_resources_.find(video_send_stream) == | 
|  | adapter_resources_.end()); | 
|  | auto adapter_resource = | 
|  | broadcast_resource_listener_.CreateAdapterResource(); | 
|  | video_send_stream->AddAdaptationResource(adapter_resource); | 
|  | adapter_resources_.insert( | 
|  | std::make_pair(video_send_stream, adapter_resource)); | 
|  | } | 
|  |  | 
|  | void OnDestroyVideoSendStream(VideoSendStream* video_send_stream) { | 
|  | auto it = adapter_resources_.find(video_send_stream); | 
|  | RTC_DCHECK(it != adapter_resources_.end()); | 
|  | broadcast_resource_listener_.RemoveAdapterResource(it->second); | 
|  | adapter_resources_.erase(it); | 
|  | } | 
|  |  | 
|  | private: | 
|  | BroadcastResourceListener broadcast_resource_listener_; | 
|  | std::map<VideoSendStream*, rtc::scoped_refptr<webrtc::Resource>> | 
|  | adapter_resources_; | 
|  | }; | 
|  |  | 
|  | class Call final : public webrtc::Call, | 
|  | public PacketReceiver, | 
|  | public TargetTransferRateObserver, | 
|  | public BitrateAllocator::LimitObserver { | 
|  | public: | 
|  | Call(Clock* clock, | 
|  | const CallConfig& config, | 
|  | std::unique_ptr<RtpTransportControllerSendInterface> transport_send, | 
|  | TaskQueueFactory* task_queue_factory); | 
|  | ~Call() override; | 
|  |  | 
|  | Call(const Call&) = delete; | 
|  | Call& operator=(const Call&) = delete; | 
|  |  | 
|  | // Implements webrtc::Call. | 
|  | PacketReceiver* Receiver() override; | 
|  |  | 
|  | webrtc::AudioSendStream* CreateAudioSendStream( | 
|  | const webrtc::AudioSendStream::Config& config) override; | 
|  | void DestroyAudioSendStream(webrtc::AudioSendStream* send_stream) override; | 
|  |  | 
|  | webrtc::AudioReceiveStreamInterface* CreateAudioReceiveStream( | 
|  | const webrtc::AudioReceiveStreamInterface::Config& config) override; | 
|  | void DestroyAudioReceiveStream( | 
|  | webrtc::AudioReceiveStreamInterface* receive_stream) override; | 
|  |  | 
|  | webrtc::VideoSendStream* CreateVideoSendStream( | 
|  | webrtc::VideoSendStream::Config config, | 
|  | VideoEncoderConfig encoder_config) override; | 
|  | webrtc::VideoSendStream* CreateVideoSendStream( | 
|  | webrtc::VideoSendStream::Config config, | 
|  | VideoEncoderConfig encoder_config, | 
|  | std::unique_ptr<FecController> fec_controller) override; | 
|  | void DestroyVideoSendStream(webrtc::VideoSendStream* send_stream) override; | 
|  |  | 
|  | webrtc::VideoReceiveStreamInterface* CreateVideoReceiveStream( | 
|  | webrtc::VideoReceiveStreamInterface::Config configuration) override; | 
|  | void DestroyVideoReceiveStream( | 
|  | webrtc::VideoReceiveStreamInterface* receive_stream) override; | 
|  |  | 
|  | FlexfecReceiveStream* CreateFlexfecReceiveStream( | 
|  | const FlexfecReceiveStream::Config config) override; | 
|  | void DestroyFlexfecReceiveStream( | 
|  | FlexfecReceiveStream* receive_stream) override; | 
|  |  | 
|  | void AddAdaptationResource(rtc::scoped_refptr<Resource> resource) override; | 
|  |  | 
|  | RtpTransportControllerSendInterface* GetTransportControllerSend() override; | 
|  |  | 
|  | Stats GetStats() const override; | 
|  |  | 
|  | const FieldTrialsView& trials() const override; | 
|  |  | 
|  | TaskQueueBase* network_thread() const override; | 
|  | TaskQueueBase* worker_thread() const override; | 
|  |  | 
|  | void DeliverRtcpPacket(rtc::CopyOnWriteBuffer packet) override; | 
|  |  | 
|  | void DeliverRtpPacket( | 
|  | MediaType media_type, | 
|  | RtpPacketReceived packet, | 
|  | OnUndemuxablePacketHandler undemuxable_packet_handler) override; | 
|  |  | 
|  | void SignalChannelNetworkState(MediaType media, NetworkState state) override; | 
|  |  | 
|  | void OnAudioTransportOverheadChanged( | 
|  | int transport_overhead_per_packet) override; | 
|  |  | 
|  | void OnLocalSsrcUpdated(webrtc::AudioReceiveStreamInterface& stream, | 
|  | uint32_t local_ssrc) override; | 
|  | void OnLocalSsrcUpdated(VideoReceiveStreamInterface& stream, | 
|  | uint32_t local_ssrc) override; | 
|  | void OnLocalSsrcUpdated(FlexfecReceiveStream& stream, | 
|  | uint32_t local_ssrc) override; | 
|  |  | 
|  | void OnUpdateSyncGroup(webrtc::AudioReceiveStreamInterface& stream, | 
|  | absl::string_view sync_group) override; | 
|  |  | 
|  | void OnSentPacket(const rtc::SentPacket& sent_packet) override; | 
|  |  | 
|  | // Implements TargetTransferRateObserver, | 
|  | void OnTargetTransferRate(TargetTransferRate msg) override; | 
|  | void OnStartRateUpdate(DataRate start_rate) override; | 
|  |  | 
|  | // Implements BitrateAllocator::LimitObserver. | 
|  | void OnAllocationLimitsChanged(BitrateAllocationLimits limits) override; | 
|  |  | 
|  | void SetClientBitratePreferences(const BitrateSettings& preferences) override; | 
|  |  | 
|  | private: | 
|  | // Thread-compatible class that collects received packet stats and exposes | 
|  | // them as UMA histograms on destruction. | 
|  | class ReceiveStats { | 
|  | public: | 
|  | explicit ReceiveStats(Clock* clock); | 
|  | ~ReceiveStats(); | 
|  |  | 
|  | void AddReceivedRtcpBytes(int bytes); | 
|  | void AddReceivedAudioBytes(int bytes, webrtc::Timestamp arrival_time); | 
|  | void AddReceivedVideoBytes(int bytes, webrtc::Timestamp arrival_time); | 
|  |  | 
|  | private: | 
|  | RTC_NO_UNIQUE_ADDRESS SequenceChecker sequence_checker_; | 
|  | RateCounter received_bytes_per_second_counter_ | 
|  | RTC_GUARDED_BY(sequence_checker_); | 
|  | RateCounter received_audio_bytes_per_second_counter_ | 
|  | RTC_GUARDED_BY(sequence_checker_); | 
|  | RateCounter received_video_bytes_per_second_counter_ | 
|  | RTC_GUARDED_BY(sequence_checker_); | 
|  | RateCounter received_rtcp_bytes_per_second_counter_ | 
|  | RTC_GUARDED_BY(sequence_checker_); | 
|  | absl::optional<Timestamp> first_received_rtp_audio_timestamp_ | 
|  | RTC_GUARDED_BY(sequence_checker_); | 
|  | absl::optional<Timestamp> last_received_rtp_audio_timestamp_ | 
|  | RTC_GUARDED_BY(sequence_checker_); | 
|  | absl::optional<Timestamp> first_received_rtp_video_timestamp_ | 
|  | RTC_GUARDED_BY(sequence_checker_); | 
|  | absl::optional<Timestamp> last_received_rtp_video_timestamp_ | 
|  | RTC_GUARDED_BY(sequence_checker_); | 
|  | }; | 
|  |  | 
|  | // Thread-compatible class that collects sent packet stats and exposes | 
|  | // them as UMA histograms on destruction, provided SetFirstPacketTime was | 
|  | // called with a non-empty packet timestamp before the destructor. | 
|  | class SendStats { | 
|  | public: | 
|  | explicit SendStats(Clock* clock); | 
|  | ~SendStats(); | 
|  |  | 
|  | void SetFirstPacketTime(absl::optional<Timestamp> first_sent_packet_time); | 
|  | void PauseSendAndPacerBitrateCounters(); | 
|  | void AddTargetBitrateSample(uint32_t target_bitrate_bps); | 
|  | void SetMinAllocatableRate(BitrateAllocationLimits limits); | 
|  |  | 
|  | private: | 
|  | RTC_NO_UNIQUE_ADDRESS SequenceChecker destructor_sequence_checker_; | 
|  | RTC_NO_UNIQUE_ADDRESS SequenceChecker sequence_checker_; | 
|  | Clock* const clock_ RTC_GUARDED_BY(destructor_sequence_checker_); | 
|  | AvgCounter estimated_send_bitrate_kbps_counter_ | 
|  | RTC_GUARDED_BY(sequence_checker_); | 
|  | AvgCounter pacer_bitrate_kbps_counter_ RTC_GUARDED_BY(sequence_checker_); | 
|  | uint32_t min_allocated_send_bitrate_bps_ RTC_GUARDED_BY(sequence_checker_){ | 
|  | 0}; | 
|  | absl::optional<Timestamp> first_sent_packet_time_ | 
|  | RTC_GUARDED_BY(destructor_sequence_checker_); | 
|  | }; | 
|  |  | 
|  | void DeliverRtcp(MediaType media_type, rtc::CopyOnWriteBuffer packet) | 
|  | RTC_RUN_ON(network_thread_); | 
|  |  | 
|  | AudioReceiveStreamImpl* FindAudioStreamForSyncGroup( | 
|  | absl::string_view sync_group) RTC_RUN_ON(worker_thread_); | 
|  | void ConfigureSync(absl::string_view sync_group) RTC_RUN_ON(worker_thread_); | 
|  |  | 
|  | void NotifyBweOfReceivedPacket(const RtpPacketReceived& packet, | 
|  | MediaType media_type) | 
|  | RTC_RUN_ON(worker_thread_); | 
|  |  | 
|  | bool RegisterReceiveStream(uint32_t ssrc, ReceiveStreamInterface* stream); | 
|  | bool UnregisterReceiveStream(uint32_t ssrc); | 
|  |  | 
|  | void UpdateAggregateNetworkState(); | 
|  |  | 
|  | // Ensure that necessary process threads are started, and any required | 
|  | // callbacks have been registered. | 
|  | void EnsureStarted() RTC_RUN_ON(worker_thread_); | 
|  |  | 
|  | Clock* const clock_; | 
|  | TaskQueueFactory* const task_queue_factory_; | 
|  | TaskQueueBase* const worker_thread_; | 
|  | TaskQueueBase* const network_thread_; | 
|  | const std::unique_ptr<DecodeSynchronizer> decode_sync_; | 
|  | RTC_NO_UNIQUE_ADDRESS SequenceChecker send_transport_sequence_checker_; | 
|  |  | 
|  | const int num_cpu_cores_; | 
|  | const std::unique_ptr<CallStats> call_stats_; | 
|  | const std::unique_ptr<BitrateAllocator> bitrate_allocator_; | 
|  | const CallConfig config_ RTC_GUARDED_BY(worker_thread_); | 
|  | // Maps to config_.trials, can be used from any thread via `trials()`. | 
|  | const FieldTrialsView& trials_; | 
|  |  | 
|  | NetworkState audio_network_state_ RTC_GUARDED_BY(worker_thread_); | 
|  | NetworkState video_network_state_ RTC_GUARDED_BY(worker_thread_); | 
|  | // TODO(bugs.webrtc.org/11993): Move aggregate_network_up_ over to the | 
|  | // network thread. | 
|  | bool aggregate_network_up_ RTC_GUARDED_BY(worker_thread_); | 
|  |  | 
|  | // Schedules nack periodic processing on behalf of all streams. | 
|  | NackPeriodicProcessor nack_periodic_processor_; | 
|  |  | 
|  | // Audio, Video, and FlexFEC receive streams are owned by the client that | 
|  | // creates them. | 
|  | // TODO(bugs.webrtc.org/11993): Move audio_receive_streams_, | 
|  | // video_receive_streams_ over to the network thread. | 
|  | std::set<AudioReceiveStreamImpl*> audio_receive_streams_ | 
|  | RTC_GUARDED_BY(worker_thread_); | 
|  | std::set<VideoReceiveStream2*> video_receive_streams_ | 
|  | RTC_GUARDED_BY(worker_thread_); | 
|  | // TODO(bugs.webrtc.org/7135, bugs.webrtc.org/9719): Should eventually be | 
|  | // injected at creation, with a single object in the bundled case. | 
|  | RtpStreamReceiverController audio_receiver_controller_ | 
|  | RTC_GUARDED_BY(worker_thread_); | 
|  | RtpStreamReceiverController video_receiver_controller_ | 
|  | RTC_GUARDED_BY(worker_thread_); | 
|  |  | 
|  | // This extra map is used for receive processing which is | 
|  | // independent of media type. | 
|  |  | 
|  | RTC_NO_UNIQUE_ADDRESS SequenceChecker receive_11993_checker_; | 
|  |  | 
|  | // Audio and Video send streams are owned by the client that creates them. | 
|  | // TODO(bugs.webrtc.org/11993): `audio_send_ssrcs_` and `video_send_ssrcs_` | 
|  | // should be accessed on the network thread. | 
|  | std::map<uint32_t, AudioSendStream*> audio_send_ssrcs_ | 
|  | RTC_GUARDED_BY(worker_thread_); | 
|  | std::map<uint32_t, VideoSendStream*> video_send_ssrcs_ | 
|  | RTC_GUARDED_BY(worker_thread_); | 
|  | std::set<VideoSendStream*> video_send_streams_ RTC_GUARDED_BY(worker_thread_); | 
|  | // True if `video_send_streams_` is empty, false if not. The atomic variable | 
|  | // is used to decide UMA send statistics behavior and enables avoiding a | 
|  | // PostTask(). | 
|  | std::atomic<bool> video_send_streams_empty_{true}; | 
|  |  | 
|  | // Each forwarder wraps an adaptation resource that was added to the call. | 
|  | std::vector<std::unique_ptr<ResourceVideoSendStreamForwarder>> | 
|  | adaptation_resource_forwarders_ RTC_GUARDED_BY(worker_thread_); | 
|  |  | 
|  | using RtpStateMap = std::map<uint32_t, RtpState>; | 
|  | RtpStateMap suspended_audio_send_ssrcs_ RTC_GUARDED_BY(worker_thread_); | 
|  | RtpStateMap suspended_video_send_ssrcs_ RTC_GUARDED_BY(worker_thread_); | 
|  |  | 
|  | using RtpPayloadStateMap = std::map<uint32_t, RtpPayloadState>; | 
|  | RtpPayloadStateMap suspended_video_payload_states_ | 
|  | RTC_GUARDED_BY(worker_thread_); | 
|  |  | 
|  | webrtc::RtcEventLog* const event_log_; | 
|  |  | 
|  | // TODO(bugs.webrtc.org/11993) ready to move stats access to the network | 
|  | // thread. | 
|  | ReceiveStats receive_stats_ RTC_GUARDED_BY(worker_thread_); | 
|  | SendStats send_stats_ RTC_GUARDED_BY(send_transport_sequence_checker_); | 
|  | // `last_bandwidth_bps_` and `configured_max_padding_bitrate_bps_` being | 
|  | // atomic avoids a PostTask. The variables are used for stats gathering. | 
|  | std::atomic<uint32_t> last_bandwidth_bps_{0}; | 
|  | std::atomic<uint32_t> configured_max_padding_bitrate_bps_{0}; | 
|  |  | 
|  | ReceiveSideCongestionController receive_side_cc_; | 
|  | RepeatingTaskHandle receive_side_cc_periodic_task_; | 
|  |  | 
|  | const std::unique_ptr<ReceiveTimeCalculator> receive_time_calculator_; | 
|  |  | 
|  | const std::unique_ptr<SendDelayStats> video_send_delay_stats_; | 
|  | const Timestamp start_of_call_; | 
|  |  | 
|  | // Note that `task_safety_` needs to be at a greater scope than the task queue | 
|  | // owned by `transport_send_` since calls might arrive on the network thread | 
|  | // while Call is being deleted and the task queue is being torn down. | 
|  | const ScopedTaskSafety task_safety_; | 
|  |  | 
|  | // Caches transport_send_.get(), to avoid racing with destructor. | 
|  | // Note that this is declared before transport_send_ to ensure that it is not | 
|  | // invalidated until no more tasks can be running on the transport_send_ task | 
|  | // queue. | 
|  | // For more details on the background of this member variable, see: | 
|  | // https://webrtc-review.googlesource.com/c/src/+/63023/9/call/call.cc | 
|  | // https://bugs.chromium.org/p/chromium/issues/detail?id=992640 | 
|  | RtpTransportControllerSendInterface* const transport_send_ptr_ | 
|  | RTC_GUARDED_BY(send_transport_sequence_checker_); | 
|  | // Declared last since it will issue callbacks from a task queue. Declaring it | 
|  | // last ensures that it is destroyed first and any running tasks are finished. | 
|  | const std::unique_ptr<RtpTransportControllerSendInterface> transport_send_; | 
|  |  | 
|  | bool is_started_ RTC_GUARDED_BY(worker_thread_) = false; | 
|  |  | 
|  | // Sequence checker for outgoing network traffic. Could be the network thread. | 
|  | // Could also be a pacer owned thread or TQ such as the TaskQueuePacedSender. | 
|  | RTC_NO_UNIQUE_ADDRESS SequenceChecker sent_packet_sequence_checker_; | 
|  | absl::optional<rtc::SentPacket> last_sent_packet_ | 
|  | RTC_GUARDED_BY(sent_packet_sequence_checker_); | 
|  | }; | 
|  | }  // namespace internal | 
|  |  | 
|  | std::string Call::Stats::ToString(int64_t time_ms) const { | 
|  | char buf[1024]; | 
|  | rtc::SimpleStringBuilder ss(buf); | 
|  | ss << "Call stats: " << time_ms << ", {"; | 
|  | ss << "send_bw_bps: " << send_bandwidth_bps << ", "; | 
|  | ss << "recv_bw_bps: " << recv_bandwidth_bps << ", "; | 
|  | ss << "max_pad_bps: " << max_padding_bitrate_bps << ", "; | 
|  | ss << "pacer_delay_ms: " << pacer_delay_ms << ", "; | 
|  | ss << "rtt_ms: " << rtt_ms; | 
|  | ss << '}'; | 
|  | return ss.str(); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<Call> Call::Create(const CallConfig& config) { | 
|  | Clock* clock = Clock::GetRealTimeClock(); | 
|  | return Create(config, clock, | 
|  | RtpTransportControllerSendFactory().Create( | 
|  | config.ExtractTransportConfig(), clock)); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<Call> Call::Create( | 
|  | const CallConfig& config, | 
|  | Clock* clock, | 
|  | std::unique_ptr<RtpTransportControllerSendInterface> | 
|  | transportControllerSend) { | 
|  | RTC_DCHECK(config.task_queue_factory); | 
|  | return std::make_unique<internal::Call>(clock, config, | 
|  | std::move(transportControllerSend), | 
|  | config.task_queue_factory); | 
|  | } | 
|  |  | 
|  | // This method here to avoid subclasses has to implement this method. | 
|  | // Call perf test will use Internal::Call::CreateVideoSendStream() to inject | 
|  | // FecController. | 
|  | VideoSendStream* Call::CreateVideoSendStream( | 
|  | VideoSendStream::Config config, | 
|  | VideoEncoderConfig encoder_config, | 
|  | std::unique_ptr<FecController> fec_controller) { | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | namespace internal { | 
|  |  | 
|  | Call::ReceiveStats::ReceiveStats(Clock* clock) | 
|  | : received_bytes_per_second_counter_(clock, nullptr, false), | 
|  | received_audio_bytes_per_second_counter_(clock, nullptr, false), | 
|  | received_video_bytes_per_second_counter_(clock, nullptr, false), | 
|  | received_rtcp_bytes_per_second_counter_(clock, nullptr, false) { | 
|  | sequence_checker_.Detach(); | 
|  | } | 
|  |  | 
|  | void Call::ReceiveStats::AddReceivedRtcpBytes(int bytes) { | 
|  | RTC_DCHECK_RUN_ON(&sequence_checker_); | 
|  | if (received_bytes_per_second_counter_.HasSample()) { | 
|  | // First RTP packet has been received. | 
|  | received_bytes_per_second_counter_.Add(static_cast<int>(bytes)); | 
|  | received_rtcp_bytes_per_second_counter_.Add(static_cast<int>(bytes)); | 
|  | } | 
|  | } | 
|  |  | 
|  | void Call::ReceiveStats::AddReceivedAudioBytes(int bytes, | 
|  | webrtc::Timestamp arrival_time) { | 
|  | RTC_DCHECK_RUN_ON(&sequence_checker_); | 
|  | received_bytes_per_second_counter_.Add(bytes); | 
|  | received_audio_bytes_per_second_counter_.Add(bytes); | 
|  | if (!first_received_rtp_audio_timestamp_) | 
|  | first_received_rtp_audio_timestamp_ = arrival_time; | 
|  | last_received_rtp_audio_timestamp_ = arrival_time; | 
|  | } | 
|  |  | 
|  | void Call::ReceiveStats::AddReceivedVideoBytes(int bytes, | 
|  | webrtc::Timestamp arrival_time) { | 
|  | RTC_DCHECK_RUN_ON(&sequence_checker_); | 
|  | received_bytes_per_second_counter_.Add(bytes); | 
|  | received_video_bytes_per_second_counter_.Add(bytes); | 
|  | if (!first_received_rtp_video_timestamp_) | 
|  | first_received_rtp_video_timestamp_ = arrival_time; | 
|  | last_received_rtp_video_timestamp_ = arrival_time; | 
|  | } | 
|  |  | 
|  | Call::ReceiveStats::~ReceiveStats() { | 
|  | RTC_DCHECK_RUN_ON(&sequence_checker_); | 
|  | if (first_received_rtp_audio_timestamp_) { | 
|  | RTC_HISTOGRAM_COUNTS_100000( | 
|  | "WebRTC.Call.TimeReceivingAudioRtpPacketsInSeconds", | 
|  | (*last_received_rtp_audio_timestamp_ - | 
|  | *first_received_rtp_audio_timestamp_) | 
|  | .seconds()); | 
|  | } | 
|  | if (first_received_rtp_video_timestamp_) { | 
|  | RTC_HISTOGRAM_COUNTS_100000( | 
|  | "WebRTC.Call.TimeReceivingVideoRtpPacketsInSeconds", | 
|  | (*last_received_rtp_video_timestamp_ - | 
|  | *first_received_rtp_video_timestamp_) | 
|  | .seconds()); | 
|  | } | 
|  | const int kMinRequiredPeriodicSamples = 5; | 
|  | AggregatedStats video_bytes_per_sec = | 
|  | received_video_bytes_per_second_counter_.GetStats(); | 
|  | if (video_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) { | 
|  | RTC_HISTOGRAM_COUNTS_100000("WebRTC.Call.VideoBitrateReceivedInKbps", | 
|  | video_bytes_per_sec.average * 8 / 1000); | 
|  | RTC_LOG(LS_INFO) << "WebRTC.Call.VideoBitrateReceivedInBps, " | 
|  | << video_bytes_per_sec.ToStringWithMultiplier(8); | 
|  | } | 
|  | AggregatedStats audio_bytes_per_sec = | 
|  | received_audio_bytes_per_second_counter_.GetStats(); | 
|  | if (audio_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) { | 
|  | RTC_HISTOGRAM_COUNTS_100000("WebRTC.Call.AudioBitrateReceivedInKbps", | 
|  | audio_bytes_per_sec.average * 8 / 1000); | 
|  | RTC_LOG(LS_INFO) << "WebRTC.Call.AudioBitrateReceivedInBps, " | 
|  | << audio_bytes_per_sec.ToStringWithMultiplier(8); | 
|  | } | 
|  | AggregatedStats rtcp_bytes_per_sec = | 
|  | received_rtcp_bytes_per_second_counter_.GetStats(); | 
|  | if (rtcp_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) { | 
|  | RTC_HISTOGRAM_COUNTS_100000("WebRTC.Call.RtcpBitrateReceivedInBps", | 
|  | rtcp_bytes_per_sec.average * 8); | 
|  | RTC_LOG(LS_INFO) << "WebRTC.Call.RtcpBitrateReceivedInBps, " | 
|  | << rtcp_bytes_per_sec.ToStringWithMultiplier(8); | 
|  | } | 
|  | AggregatedStats recv_bytes_per_sec = | 
|  | received_bytes_per_second_counter_.GetStats(); | 
|  | if (recv_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) { | 
|  | RTC_HISTOGRAM_COUNTS_100000("WebRTC.Call.BitrateReceivedInKbps", | 
|  | recv_bytes_per_sec.average * 8 / 1000); | 
|  | RTC_LOG(LS_INFO) << "WebRTC.Call.BitrateReceivedInBps, " | 
|  | << recv_bytes_per_sec.ToStringWithMultiplier(8); | 
|  | } | 
|  | } | 
|  |  | 
|  | Call::SendStats::SendStats(Clock* clock) | 
|  | : clock_(clock), | 
|  | estimated_send_bitrate_kbps_counter_(clock, nullptr, true), | 
|  | pacer_bitrate_kbps_counter_(clock, nullptr, true) { | 
|  | destructor_sequence_checker_.Detach(); | 
|  | sequence_checker_.Detach(); | 
|  | } | 
|  |  | 
|  | Call::SendStats::~SendStats() { | 
|  | RTC_DCHECK_RUN_ON(&destructor_sequence_checker_); | 
|  | if (!first_sent_packet_time_) | 
|  | return; | 
|  |  | 
|  | TimeDelta elapsed = clock_->CurrentTime() - *first_sent_packet_time_; | 
|  | if (elapsed.seconds() < metrics::kMinRunTimeInSeconds) | 
|  | return; | 
|  |  | 
|  | const int kMinRequiredPeriodicSamples = 5; | 
|  | AggregatedStats send_bitrate_stats = | 
|  | estimated_send_bitrate_kbps_counter_.ProcessAndGetStats(); | 
|  | if (send_bitrate_stats.num_samples > kMinRequiredPeriodicSamples) { | 
|  | RTC_HISTOGRAM_COUNTS_100000("WebRTC.Call.EstimatedSendBitrateInKbps", | 
|  | send_bitrate_stats.average); | 
|  | RTC_LOG(LS_INFO) << "WebRTC.Call.EstimatedSendBitrateInKbps, " | 
|  | << send_bitrate_stats.ToString(); | 
|  | } | 
|  | AggregatedStats pacer_bitrate_stats = | 
|  | pacer_bitrate_kbps_counter_.ProcessAndGetStats(); | 
|  | if (pacer_bitrate_stats.num_samples > kMinRequiredPeriodicSamples) { | 
|  | RTC_HISTOGRAM_COUNTS_100000("WebRTC.Call.PacerBitrateInKbps", | 
|  | pacer_bitrate_stats.average); | 
|  | RTC_LOG(LS_INFO) << "WebRTC.Call.PacerBitrateInKbps, " | 
|  | << pacer_bitrate_stats.ToString(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void Call::SendStats::SetFirstPacketTime( | 
|  | absl::optional<Timestamp> first_sent_packet_time) { | 
|  | RTC_DCHECK_RUN_ON(&destructor_sequence_checker_); | 
|  | first_sent_packet_time_ = first_sent_packet_time; | 
|  | } | 
|  |  | 
|  | void Call::SendStats::PauseSendAndPacerBitrateCounters() { | 
|  | RTC_DCHECK_RUN_ON(&sequence_checker_); | 
|  | estimated_send_bitrate_kbps_counter_.ProcessAndPause(); | 
|  | pacer_bitrate_kbps_counter_.ProcessAndPause(); | 
|  | } | 
|  |  | 
|  | void Call::SendStats::AddTargetBitrateSample(uint32_t target_bitrate_bps) { | 
|  | RTC_DCHECK_RUN_ON(&sequence_checker_); | 
|  | estimated_send_bitrate_kbps_counter_.Add(target_bitrate_bps / 1000); | 
|  | // Pacer bitrate may be higher than bitrate estimate if enforcing min | 
|  | // bitrate. | 
|  | uint32_t pacer_bitrate_bps = | 
|  | std::max(target_bitrate_bps, min_allocated_send_bitrate_bps_); | 
|  | pacer_bitrate_kbps_counter_.Add(pacer_bitrate_bps / 1000); | 
|  | } | 
|  |  | 
|  | void Call::SendStats::SetMinAllocatableRate(BitrateAllocationLimits limits) { | 
|  | RTC_DCHECK_RUN_ON(&sequence_checker_); | 
|  | min_allocated_send_bitrate_bps_ = limits.min_allocatable_rate.bps(); | 
|  | } | 
|  |  | 
|  | Call::Call(Clock* clock, | 
|  | const CallConfig& config, | 
|  | std::unique_ptr<RtpTransportControllerSendInterface> transport_send, | 
|  | TaskQueueFactory* task_queue_factory) | 
|  | : clock_(clock), | 
|  | task_queue_factory_(task_queue_factory), | 
|  | worker_thread_(GetCurrentTaskQueueOrThread()), | 
|  | // If `network_task_queue_` was set to nullptr, network related calls | 
|  | // must be made on `worker_thread_` (i.e. they're one and the same). | 
|  | network_thread_(config.network_task_queue_ ? config.network_task_queue_ | 
|  | : worker_thread_), | 
|  | decode_sync_(config.metronome | 
|  | ? std::make_unique<DecodeSynchronizer>(clock_, | 
|  | config.metronome, | 
|  | worker_thread_) | 
|  | : nullptr), | 
|  | num_cpu_cores_(CpuInfo::DetectNumberOfCores()), | 
|  | call_stats_(new CallStats(clock_, worker_thread_)), | 
|  | bitrate_allocator_(new BitrateAllocator(this)), | 
|  | config_(config), | 
|  | trials_(*config.trials), | 
|  | audio_network_state_(kNetworkDown), | 
|  | video_network_state_(kNetworkDown), | 
|  | aggregate_network_up_(false), | 
|  | event_log_(config.event_log), | 
|  | receive_stats_(clock_), | 
|  | send_stats_(clock_), | 
|  | receive_side_cc_(clock, | 
|  | absl::bind_front(&PacketRouter::SendCombinedRtcpPacket, | 
|  | transport_send->packet_router()), | 
|  | absl::bind_front(&PacketRouter::SendRemb, | 
|  | transport_send->packet_router()), | 
|  | /*network_state_estimator=*/nullptr), | 
|  | receive_time_calculator_( | 
|  | ReceiveTimeCalculator::CreateFromFieldTrial(*config.trials)), | 
|  | video_send_delay_stats_(new SendDelayStats(clock_)), | 
|  | start_of_call_(clock_->CurrentTime()), | 
|  | transport_send_ptr_(transport_send.get()), | 
|  | transport_send_(std::move(transport_send)) { | 
|  | RTC_DCHECK(config.event_log != nullptr); | 
|  | RTC_DCHECK(config.trials != nullptr); | 
|  | RTC_DCHECK(network_thread_); | 
|  | RTC_DCHECK(worker_thread_->IsCurrent()); | 
|  |  | 
|  | receive_11993_checker_.Detach(); | 
|  | send_transport_sequence_checker_.Detach(); | 
|  | sent_packet_sequence_checker_.Detach(); | 
|  |  | 
|  | // Do not remove this call; it is here to convince the compiler that the | 
|  | // WebRTC source timestamp string needs to be in the final binary. | 
|  | LoadWebRTCVersionInRegister(); | 
|  |  | 
|  | call_stats_->RegisterStatsObserver(&receive_side_cc_); | 
|  |  | 
|  | ReceiveSideCongestionController* receive_side_cc = &receive_side_cc_; | 
|  | receive_side_cc_periodic_task_ = RepeatingTaskHandle::Start( | 
|  | worker_thread_, | 
|  | [receive_side_cc] { return receive_side_cc->MaybeProcess(); }, | 
|  | TaskQueueBase::DelayPrecision::kLow, clock_); | 
|  | } | 
|  |  | 
|  | Call::~Call() { | 
|  | RTC_DCHECK_RUN_ON(worker_thread_); | 
|  |  | 
|  | RTC_CHECK(audio_send_ssrcs_.empty()); | 
|  | RTC_CHECK(video_send_ssrcs_.empty()); | 
|  | RTC_CHECK(video_send_streams_.empty()); | 
|  | RTC_CHECK(audio_receive_streams_.empty()); | 
|  | RTC_CHECK(video_receive_streams_.empty()); | 
|  |  | 
|  | receive_side_cc_periodic_task_.Stop(); | 
|  | call_stats_->DeregisterStatsObserver(&receive_side_cc_); | 
|  | send_stats_.SetFirstPacketTime(transport_send_->GetFirstPacketTime()); | 
|  |  | 
|  | RTC_HISTOGRAM_COUNTS_100000( | 
|  | "WebRTC.Call.LifetimeInSeconds", | 
|  | (clock_->CurrentTime() - start_of_call_).seconds()); | 
|  | } | 
|  |  | 
|  | void Call::EnsureStarted() { | 
|  | if (is_started_) { | 
|  | return; | 
|  | } | 
|  | is_started_ = true; | 
|  |  | 
|  | call_stats_->EnsureStarted(); | 
|  |  | 
|  | // This call seems to kick off a number of things, so probably better left | 
|  | // off being kicked off on request rather than in the ctor. | 
|  | transport_send_->RegisterTargetTransferRateObserver(this); | 
|  |  | 
|  | transport_send_->EnsureStarted(); | 
|  | } | 
|  |  | 
|  | void Call::SetClientBitratePreferences(const BitrateSettings& preferences) { | 
|  | RTC_DCHECK_RUN_ON(worker_thread_); | 
|  | GetTransportControllerSend()->SetClientBitratePreferences(preferences); | 
|  | } | 
|  |  | 
|  | PacketReceiver* Call::Receiver() { | 
|  | return this; | 
|  | } | 
|  |  | 
|  | webrtc::AudioSendStream* Call::CreateAudioSendStream( | 
|  | const webrtc::AudioSendStream::Config& config) { | 
|  | TRACE_EVENT0("webrtc", "Call::CreateAudioSendStream"); | 
|  | RTC_DCHECK_RUN_ON(worker_thread_); | 
|  |  | 
|  | EnsureStarted(); | 
|  |  | 
|  | // Stream config is logged in AudioSendStream::ConfigureStream, as it may | 
|  | // change during the stream's lifetime. | 
|  | absl::optional<RtpState> suspended_rtp_state; | 
|  | { | 
|  | const auto& iter = suspended_audio_send_ssrcs_.find(config.rtp.ssrc); | 
|  | if (iter != suspended_audio_send_ssrcs_.end()) { | 
|  | suspended_rtp_state.emplace(iter->second); | 
|  | } | 
|  | } | 
|  |  | 
|  | AudioSendStream* send_stream = new AudioSendStream( | 
|  | clock_, config, config_.audio_state, task_queue_factory_, | 
|  | transport_send_.get(), bitrate_allocator_.get(), event_log_, | 
|  | call_stats_->AsRtcpRttStats(), suspended_rtp_state, trials()); | 
|  | RTC_DCHECK(audio_send_ssrcs_.find(config.rtp.ssrc) == | 
|  | audio_send_ssrcs_.end()); | 
|  | audio_send_ssrcs_[config.rtp.ssrc] = send_stream; | 
|  |  | 
|  | // TODO(bugs.webrtc.org/11993): call AssociateSendStream and | 
|  | // UpdateAggregateNetworkState asynchronously on the network thread. | 
|  | for (AudioReceiveStreamImpl* stream : audio_receive_streams_) { | 
|  | if (stream->local_ssrc() == config.rtp.ssrc) { | 
|  | stream->AssociateSendStream(send_stream); | 
|  | } | 
|  | } | 
|  |  | 
|  | UpdateAggregateNetworkState(); | 
|  |  | 
|  | return send_stream; | 
|  | } | 
|  |  | 
|  | void Call::DestroyAudioSendStream(webrtc::AudioSendStream* send_stream) { | 
|  | TRACE_EVENT0("webrtc", "Call::DestroyAudioSendStream"); | 
|  | RTC_DCHECK_RUN_ON(worker_thread_); | 
|  | RTC_DCHECK(send_stream != nullptr); | 
|  |  | 
|  | send_stream->Stop(); | 
|  |  | 
|  | const uint32_t ssrc = send_stream->GetConfig().rtp.ssrc; | 
|  | webrtc::internal::AudioSendStream* audio_send_stream = | 
|  | static_cast<webrtc::internal::AudioSendStream*>(send_stream); | 
|  | suspended_audio_send_ssrcs_[ssrc] = audio_send_stream->GetRtpState(); | 
|  |  | 
|  | size_t num_deleted = audio_send_ssrcs_.erase(ssrc); | 
|  | RTC_DCHECK_EQ(1, num_deleted); | 
|  |  | 
|  | // TODO(bugs.webrtc.org/11993): call AssociateSendStream and | 
|  | // UpdateAggregateNetworkState asynchronously on the network thread. | 
|  | for (AudioReceiveStreamImpl* stream : audio_receive_streams_) { | 
|  | if (stream->local_ssrc() == ssrc) { | 
|  | stream->AssociateSendStream(nullptr); | 
|  | } | 
|  | } | 
|  |  | 
|  | UpdateAggregateNetworkState(); | 
|  |  | 
|  | delete send_stream; | 
|  | } | 
|  |  | 
|  | webrtc::AudioReceiveStreamInterface* Call::CreateAudioReceiveStream( | 
|  | const webrtc::AudioReceiveStreamInterface::Config& config) { | 
|  | TRACE_EVENT0("webrtc", "Call::CreateAudioReceiveStream"); | 
|  | RTC_DCHECK_RUN_ON(worker_thread_); | 
|  | EnsureStarted(); | 
|  | event_log_->Log(std::make_unique<RtcEventAudioReceiveStreamConfig>( | 
|  | CreateRtcLogStreamConfig(config))); | 
|  |  | 
|  | AudioReceiveStreamImpl* receive_stream = new AudioReceiveStreamImpl( | 
|  | clock_, transport_send_->packet_router(), config_.neteq_factory, config, | 
|  | config_.audio_state, event_log_); | 
|  | audio_receive_streams_.insert(receive_stream); | 
|  |  | 
|  | // TODO(bugs.webrtc.org/11993): Make the registration on the network thread | 
|  | // (asynchronously). The registration and `audio_receiver_controller_` need | 
|  | // to live on the network thread. | 
|  | receive_stream->RegisterWithTransport(&audio_receiver_controller_); | 
|  |  | 
|  | ConfigureSync(config.sync_group); | 
|  |  | 
|  | auto it = audio_send_ssrcs_.find(config.rtp.local_ssrc); | 
|  | if (it != audio_send_ssrcs_.end()) { | 
|  | receive_stream->AssociateSendStream(it->second); | 
|  | } | 
|  |  | 
|  | UpdateAggregateNetworkState(); | 
|  | return receive_stream; | 
|  | } | 
|  |  | 
|  | void Call::DestroyAudioReceiveStream( | 
|  | webrtc::AudioReceiveStreamInterface* receive_stream) { | 
|  | TRACE_EVENT0("webrtc", "Call::DestroyAudioReceiveStream"); | 
|  | RTC_DCHECK_RUN_ON(worker_thread_); | 
|  | RTC_DCHECK(receive_stream != nullptr); | 
|  | webrtc::AudioReceiveStreamImpl* audio_receive_stream = | 
|  | static_cast<webrtc::AudioReceiveStreamImpl*>(receive_stream); | 
|  |  | 
|  | // TODO(bugs.webrtc.org/11993): Access the map, rtp config, call ConfigureSync | 
|  | // and UpdateAggregateNetworkState on the network thread. The call to | 
|  | // `UnregisterFromTransport` should also happen on the network thread. | 
|  | audio_receive_stream->UnregisterFromTransport(); | 
|  |  | 
|  | uint32_t ssrc = audio_receive_stream->remote_ssrc(); | 
|  | receive_side_cc_.RemoveStream(ssrc); | 
|  |  | 
|  | audio_receive_streams_.erase(audio_receive_stream); | 
|  |  | 
|  | // After calling erase(), call ConfigureSync. This will clear associated | 
|  | // video streams or associate them with a different audio stream if one exists | 
|  | // for this sync_group. | 
|  | ConfigureSync(audio_receive_stream->sync_group()); | 
|  |  | 
|  | UpdateAggregateNetworkState(); | 
|  | // TODO(bugs.webrtc.org/11993): Consider if deleting `audio_receive_stream` | 
|  | // on the network thread would be better or if we'd need to tear down the | 
|  | // state in two phases. | 
|  | delete audio_receive_stream; | 
|  | } | 
|  |  | 
|  | // This method can be used for Call tests with external fec controller factory. | 
|  | webrtc::VideoSendStream* Call::CreateVideoSendStream( | 
|  | webrtc::VideoSendStream::Config config, | 
|  | VideoEncoderConfig encoder_config, | 
|  | std::unique_ptr<FecController> fec_controller) { | 
|  | TRACE_EVENT0("webrtc", "Call::CreateVideoSendStream"); | 
|  | RTC_DCHECK_RUN_ON(worker_thread_); | 
|  |  | 
|  | EnsureStarted(); | 
|  |  | 
|  | video_send_delay_stats_->AddSsrcs(config); | 
|  | for (size_t ssrc_index = 0; ssrc_index < config.rtp.ssrcs.size(); | 
|  | ++ssrc_index) { | 
|  | event_log_->Log(std::make_unique<RtcEventVideoSendStreamConfig>( | 
|  | CreateRtcLogStreamConfig(config, ssrc_index))); | 
|  | } | 
|  |  | 
|  | // TODO(mflodman): Base the start bitrate on a current bandwidth estimate, if | 
|  | // the call has already started. | 
|  | // Copy ssrcs from `config` since `config` is moved. | 
|  | std::vector<uint32_t> ssrcs = config.rtp.ssrcs; | 
|  |  | 
|  | VideoSendStream* send_stream = new VideoSendStream( | 
|  | clock_, num_cpu_cores_, task_queue_factory_, network_thread_, | 
|  | call_stats_->AsRtcpRttStats(), transport_send_.get(), | 
|  | bitrate_allocator_.get(), video_send_delay_stats_.get(), event_log_, | 
|  | std::move(config), std::move(encoder_config), suspended_video_send_ssrcs_, | 
|  | suspended_video_payload_states_, std::move(fec_controller), | 
|  | *config_.trials); | 
|  |  | 
|  | for (uint32_t ssrc : ssrcs) { | 
|  | RTC_DCHECK(video_send_ssrcs_.find(ssrc) == video_send_ssrcs_.end()); | 
|  | video_send_ssrcs_[ssrc] = send_stream; | 
|  | } | 
|  | video_send_streams_.insert(send_stream); | 
|  | video_send_streams_empty_.store(false, std::memory_order_relaxed); | 
|  |  | 
|  | // Forward resources that were previously added to the call to the new stream. | 
|  | for (const auto& resource_forwarder : adaptation_resource_forwarders_) { | 
|  | resource_forwarder->OnCreateVideoSendStream(send_stream); | 
|  | } | 
|  |  | 
|  | UpdateAggregateNetworkState(); | 
|  |  | 
|  | return send_stream; | 
|  | } | 
|  |  | 
|  | webrtc::VideoSendStream* Call::CreateVideoSendStream( | 
|  | webrtc::VideoSendStream::Config config, | 
|  | VideoEncoderConfig encoder_config) { | 
|  | RTC_DCHECK_RUN_ON(worker_thread_); | 
|  | if (config_.fec_controller_factory) { | 
|  | RTC_LOG(LS_INFO) << "External FEC Controller will be used."; | 
|  | } | 
|  | std::unique_ptr<FecController> fec_controller = | 
|  | config_.fec_controller_factory | 
|  | ? config_.fec_controller_factory->CreateFecController() | 
|  | : std::make_unique<FecControllerDefault>(clock_); | 
|  | return CreateVideoSendStream(std::move(config), std::move(encoder_config), | 
|  | std::move(fec_controller)); | 
|  | } | 
|  |  | 
|  | void Call::DestroyVideoSendStream(webrtc::VideoSendStream* send_stream) { | 
|  | TRACE_EVENT0("webrtc", "Call::DestroyVideoSendStream"); | 
|  | RTC_DCHECK(send_stream != nullptr); | 
|  | RTC_DCHECK_RUN_ON(worker_thread_); | 
|  |  | 
|  | VideoSendStream* send_stream_impl = | 
|  | static_cast<VideoSendStream*>(send_stream); | 
|  |  | 
|  | auto it = video_send_ssrcs_.begin(); | 
|  | while (it != video_send_ssrcs_.end()) { | 
|  | if (it->second == static_cast<VideoSendStream*>(send_stream)) { | 
|  | send_stream_impl = it->second; | 
|  | video_send_ssrcs_.erase(it++); | 
|  | } else { | 
|  | ++it; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Stop forwarding resources to the stream being destroyed. | 
|  | for (const auto& resource_forwarder : adaptation_resource_forwarders_) { | 
|  | resource_forwarder->OnDestroyVideoSendStream(send_stream_impl); | 
|  | } | 
|  | video_send_streams_.erase(send_stream_impl); | 
|  | if (video_send_streams_.empty()) | 
|  | video_send_streams_empty_.store(true, std::memory_order_relaxed); | 
|  |  | 
|  | VideoSendStream::RtpStateMap rtp_states; | 
|  | VideoSendStream::RtpPayloadStateMap rtp_payload_states; | 
|  | send_stream_impl->StopPermanentlyAndGetRtpStates(&rtp_states, | 
|  | &rtp_payload_states); | 
|  | for (const auto& kv : rtp_states) { | 
|  | suspended_video_send_ssrcs_[kv.first] = kv.second; | 
|  | } | 
|  | for (const auto& kv : rtp_payload_states) { | 
|  | suspended_video_payload_states_[kv.first] = kv.second; | 
|  | } | 
|  |  | 
|  | UpdateAggregateNetworkState(); | 
|  | // TODO(tommi): consider deleting on the same thread as runs | 
|  | // StopPermanentlyAndGetRtpStates. | 
|  | delete send_stream_impl; | 
|  | } | 
|  |  | 
|  | webrtc::VideoReceiveStreamInterface* Call::CreateVideoReceiveStream( | 
|  | webrtc::VideoReceiveStreamInterface::Config configuration) { | 
|  | TRACE_EVENT0("webrtc", "Call::CreateVideoReceiveStream"); | 
|  | RTC_DCHECK_RUN_ON(worker_thread_); | 
|  |  | 
|  | EnsureStarted(); | 
|  |  | 
|  | event_log_->Log(std::make_unique<RtcEventVideoReceiveStreamConfig>( | 
|  | CreateRtcLogStreamConfig(configuration))); | 
|  |  | 
|  | // TODO(bugs.webrtc.org/11993): Move the registration between `receive_stream` | 
|  | // and `video_receiver_controller_` out of VideoReceiveStream2 construction | 
|  | // and set it up asynchronously on the network thread (the registration and | 
|  | // `video_receiver_controller_` need to live on the network thread). | 
|  | // TODO(crbug.com/1381982): Re-enable decode synchronizer once the Chromium | 
|  | // API has adapted to the new Metronome interface. | 
|  | VideoReceiveStream2* receive_stream = new VideoReceiveStream2( | 
|  | task_queue_factory_, this, num_cpu_cores_, | 
|  | transport_send_->packet_router(), std::move(configuration), | 
|  | call_stats_.get(), clock_, std::make_unique<VCMTiming>(clock_, trials()), | 
|  | &nack_periodic_processor_, decode_sync_.get(), event_log_); | 
|  | // TODO(bugs.webrtc.org/11993): Set this up asynchronously on the network | 
|  | // thread. | 
|  | receive_stream->RegisterWithTransport(&video_receiver_controller_); | 
|  | video_receive_streams_.insert(receive_stream); | 
|  |  | 
|  | ConfigureSync(receive_stream->sync_group()); | 
|  |  | 
|  | receive_stream->SignalNetworkState(video_network_state_); | 
|  | UpdateAggregateNetworkState(); | 
|  | return receive_stream; | 
|  | } | 
|  |  | 
|  | void Call::DestroyVideoReceiveStream( | 
|  | webrtc::VideoReceiveStreamInterface* receive_stream) { | 
|  | TRACE_EVENT0("webrtc", "Call::DestroyVideoReceiveStream"); | 
|  | RTC_DCHECK_RUN_ON(worker_thread_); | 
|  | RTC_DCHECK(receive_stream != nullptr); | 
|  | VideoReceiveStream2* receive_stream_impl = | 
|  | static_cast<VideoReceiveStream2*>(receive_stream); | 
|  | // TODO(bugs.webrtc.org/11993): Unregister on the network thread. | 
|  | receive_stream_impl->UnregisterFromTransport(); | 
|  | video_receive_streams_.erase(receive_stream_impl); | 
|  | ConfigureSync(receive_stream_impl->sync_group()); | 
|  |  | 
|  | receive_side_cc_.RemoveStream(receive_stream_impl->remote_ssrc()); | 
|  |  | 
|  | UpdateAggregateNetworkState(); | 
|  | delete receive_stream_impl; | 
|  | } | 
|  |  | 
|  | FlexfecReceiveStream* Call::CreateFlexfecReceiveStream( | 
|  | const FlexfecReceiveStream::Config config) { | 
|  | TRACE_EVENT0("webrtc", "Call::CreateFlexfecReceiveStream"); | 
|  | RTC_DCHECK_RUN_ON(worker_thread_); | 
|  |  | 
|  | // Unlike the video and audio receive streams, FlexfecReceiveStream implements | 
|  | // RtpPacketSinkInterface itself, and hence its constructor passes its `this` | 
|  | // pointer to video_receiver_controller_->CreateStream(). Calling the | 
|  | // constructor while on the worker thread ensures that we don't call | 
|  | // OnRtpPacket until the constructor is finished and the object is | 
|  | // in a valid state, since OnRtpPacket runs on the same thread. | 
|  | FlexfecReceiveStreamImpl* receive_stream = new FlexfecReceiveStreamImpl( | 
|  | clock_, std::move(config), &video_receiver_controller_, | 
|  | call_stats_->AsRtcpRttStats()); | 
|  |  | 
|  | // TODO(bugs.webrtc.org/11993): Set this up asynchronously on the network | 
|  | // thread. | 
|  | receive_stream->RegisterWithTransport(&video_receiver_controller_); | 
|  | // TODO(brandtr): Store config in RtcEventLog here. | 
|  |  | 
|  | return receive_stream; | 
|  | } | 
|  |  | 
|  | void Call::DestroyFlexfecReceiveStream(FlexfecReceiveStream* receive_stream) { | 
|  | TRACE_EVENT0("webrtc", "Call::DestroyFlexfecReceiveStream"); | 
|  | RTC_DCHECK_RUN_ON(worker_thread_); | 
|  |  | 
|  | FlexfecReceiveStreamImpl* receive_stream_impl = | 
|  | static_cast<FlexfecReceiveStreamImpl*>(receive_stream); | 
|  | // TODO(bugs.webrtc.org/11993): Unregister on the network thread. | 
|  | receive_stream_impl->UnregisterFromTransport(); | 
|  |  | 
|  | auto ssrc = receive_stream_impl->remote_ssrc(); | 
|  | // Remove all SSRCs pointing to the FlexfecReceiveStreamImpl to be | 
|  | // destroyed. | 
|  | receive_side_cc_.RemoveStream(ssrc); | 
|  |  | 
|  | delete receive_stream_impl; | 
|  | } | 
|  |  | 
|  | void Call::AddAdaptationResource(rtc::scoped_refptr<Resource> resource) { | 
|  | RTC_DCHECK_RUN_ON(worker_thread_); | 
|  | adaptation_resource_forwarders_.push_back( | 
|  | std::make_unique<ResourceVideoSendStreamForwarder>(resource)); | 
|  | const auto& resource_forwarder = adaptation_resource_forwarders_.back(); | 
|  | for (VideoSendStream* send_stream : video_send_streams_) { | 
|  | resource_forwarder->OnCreateVideoSendStream(send_stream); | 
|  | } | 
|  | } | 
|  |  | 
|  | RtpTransportControllerSendInterface* Call::GetTransportControllerSend() { | 
|  | return transport_send_.get(); | 
|  | } | 
|  |  | 
|  | Call::Stats Call::GetStats() const { | 
|  | RTC_DCHECK_RUN_ON(worker_thread_); | 
|  |  | 
|  | Stats stats; | 
|  | // TODO(srte): It is unclear if we only want to report queues if network is | 
|  | // available. | 
|  | stats.pacer_delay_ms = | 
|  | aggregate_network_up_ ? transport_send_->GetPacerQueuingDelayMs() : 0; | 
|  |  | 
|  | stats.rtt_ms = call_stats_->LastProcessedRtt(); | 
|  |  | 
|  | // Fetch available send/receive bitrates. | 
|  | stats.recv_bandwidth_bps = receive_side_cc_.LatestReceiveSideEstimate().bps(); | 
|  | stats.send_bandwidth_bps = | 
|  | last_bandwidth_bps_.load(std::memory_order_relaxed); | 
|  | stats.max_padding_bitrate_bps = | 
|  | configured_max_padding_bitrate_bps_.load(std::memory_order_relaxed); | 
|  |  | 
|  | return stats; | 
|  | } | 
|  |  | 
|  | const FieldTrialsView& Call::trials() const { | 
|  | return trials_; | 
|  | } | 
|  |  | 
|  | TaskQueueBase* Call::network_thread() const { | 
|  | return network_thread_; | 
|  | } | 
|  |  | 
|  | TaskQueueBase* Call::worker_thread() const { | 
|  | return worker_thread_; | 
|  | } | 
|  |  | 
|  | void Call::SignalChannelNetworkState(MediaType media, NetworkState state) { | 
|  | RTC_DCHECK_RUN_ON(network_thread_); | 
|  | RTC_DCHECK(media == MediaType::AUDIO || media == MediaType::VIDEO); | 
|  |  | 
|  | auto closure = [this, media, state]() { | 
|  | // TODO(bugs.webrtc.org/11993): Move this over to the network thread. | 
|  | RTC_DCHECK_RUN_ON(worker_thread_); | 
|  | if (media == MediaType::AUDIO) { | 
|  | audio_network_state_ = state; | 
|  | } else { | 
|  | RTC_DCHECK_EQ(media, MediaType::VIDEO); | 
|  | video_network_state_ = state; | 
|  | } | 
|  |  | 
|  | // TODO(tommi): Is it necessary to always do this, including if there | 
|  | // was no change in state? | 
|  | UpdateAggregateNetworkState(); | 
|  |  | 
|  | // TODO(tommi): Is it right to do this if media == AUDIO? | 
|  | for (VideoReceiveStream2* video_receive_stream : video_receive_streams_) { | 
|  | video_receive_stream->SignalNetworkState(video_network_state_); | 
|  | } | 
|  | }; | 
|  |  | 
|  | if (network_thread_ == worker_thread_) { | 
|  | closure(); | 
|  | } else { | 
|  | // TODO(bugs.webrtc.org/11993): Remove workaround when we no longer need to | 
|  | // post to the worker thread. | 
|  | worker_thread_->PostTask(SafeTask(task_safety_.flag(), std::move(closure))); | 
|  | } | 
|  | } | 
|  |  | 
|  | void Call::OnAudioTransportOverheadChanged(int transport_overhead_per_packet) { | 
|  | RTC_DCHECK_RUN_ON(network_thread_); | 
|  | worker_thread_->PostTask( | 
|  | SafeTask(task_safety_.flag(), [this, transport_overhead_per_packet]() { | 
|  | // TODO(bugs.webrtc.org/11993): Move this over to the network thread. | 
|  | RTC_DCHECK_RUN_ON(worker_thread_); | 
|  | for (auto& kv : audio_send_ssrcs_) { | 
|  | kv.second->SetTransportOverhead(transport_overhead_per_packet); | 
|  | } | 
|  | })); | 
|  | } | 
|  |  | 
|  | void Call::UpdateAggregateNetworkState() { | 
|  | // TODO(bugs.webrtc.org/11993): Move this over to the network thread. | 
|  | // RTC_DCHECK_RUN_ON(network_thread_); | 
|  |  | 
|  | RTC_DCHECK_RUN_ON(worker_thread_); | 
|  |  | 
|  | bool have_audio = | 
|  | !audio_send_ssrcs_.empty() || !audio_receive_streams_.empty(); | 
|  | bool have_video = | 
|  | !video_send_ssrcs_.empty() || !video_receive_streams_.empty(); | 
|  |  | 
|  | bool aggregate_network_up = | 
|  | ((have_video && video_network_state_ == kNetworkUp) || | 
|  | (have_audio && audio_network_state_ == kNetworkUp)); | 
|  |  | 
|  | if (aggregate_network_up != aggregate_network_up_) { | 
|  | RTC_LOG(LS_INFO) | 
|  | << "UpdateAggregateNetworkState: aggregate_state change to " | 
|  | << (aggregate_network_up ? "up" : "down"); | 
|  | } else { | 
|  | RTC_LOG(LS_VERBOSE) | 
|  | << "UpdateAggregateNetworkState: aggregate_state remains at " | 
|  | << (aggregate_network_up ? "up" : "down"); | 
|  | } | 
|  | aggregate_network_up_ = aggregate_network_up; | 
|  |  | 
|  | transport_send_->OnNetworkAvailability(aggregate_network_up); | 
|  | } | 
|  |  | 
|  | void Call::OnLocalSsrcUpdated(webrtc::AudioReceiveStreamInterface& stream, | 
|  | uint32_t local_ssrc) { | 
|  | RTC_DCHECK_RUN_ON(worker_thread_); | 
|  | webrtc::AudioReceiveStreamImpl& receive_stream = | 
|  | static_cast<webrtc::AudioReceiveStreamImpl&>(stream); | 
|  |  | 
|  | receive_stream.SetLocalSsrc(local_ssrc); | 
|  | auto it = audio_send_ssrcs_.find(local_ssrc); | 
|  | receive_stream.AssociateSendStream(it != audio_send_ssrcs_.end() ? it->second | 
|  | : nullptr); | 
|  | } | 
|  |  | 
|  | void Call::OnLocalSsrcUpdated(VideoReceiveStreamInterface& stream, | 
|  | uint32_t local_ssrc) { | 
|  | RTC_DCHECK_RUN_ON(worker_thread_); | 
|  | static_cast<VideoReceiveStream2&>(stream).SetLocalSsrc(local_ssrc); | 
|  | } | 
|  |  | 
|  | void Call::OnLocalSsrcUpdated(FlexfecReceiveStream& stream, | 
|  | uint32_t local_ssrc) { | 
|  | RTC_DCHECK_RUN_ON(worker_thread_); | 
|  | static_cast<FlexfecReceiveStreamImpl&>(stream).SetLocalSsrc(local_ssrc); | 
|  | } | 
|  |  | 
|  | void Call::OnUpdateSyncGroup(webrtc::AudioReceiveStreamInterface& stream, | 
|  | absl::string_view sync_group) { | 
|  | RTC_DCHECK_RUN_ON(worker_thread_); | 
|  | webrtc::AudioReceiveStreamImpl& receive_stream = | 
|  | static_cast<webrtc::AudioReceiveStreamImpl&>(stream); | 
|  | receive_stream.SetSyncGroup(sync_group); | 
|  | ConfigureSync(sync_group); | 
|  | } | 
|  |  | 
|  | void Call::OnSentPacket(const rtc::SentPacket& sent_packet) { | 
|  | RTC_DCHECK_RUN_ON(&sent_packet_sequence_checker_); | 
|  | // When bundling is in effect, multiple senders may be sharing the same | 
|  | // transport. It means every |sent_packet| will be multiply notified from | 
|  | // different channels, WebRtcVoiceMediaChannel or WebRtcVideoChannel. Record | 
|  | // |last_sent_packet_| to deduplicate redundant notifications to downstream. | 
|  | // (https://crbug.com/webrtc/13437): Pass all packets without a |packet_id| to | 
|  | // downstream. | 
|  | if (last_sent_packet_.has_value() && last_sent_packet_->packet_id != -1 && | 
|  | last_sent_packet_->packet_id == sent_packet.packet_id && | 
|  | last_sent_packet_->send_time_ms == sent_packet.send_time_ms) { | 
|  | return; | 
|  | } | 
|  | last_sent_packet_ = sent_packet; | 
|  |  | 
|  | // In production and with most tests, this method will be called on the | 
|  | // network thread. However some test classes such as DirectTransport don't | 
|  | // incorporate a network thread. This means that tests for RtpSenderEgress | 
|  | // and ModuleRtpRtcpImpl2 that use DirectTransport, will call this method | 
|  | // on a ProcessThread. This is alright as is since we forward the call to | 
|  | // implementations that either just do a PostTask or use locking. | 
|  | video_send_delay_stats_->OnSentPacket(sent_packet.packet_id, | 
|  | clock_->CurrentTime()); | 
|  | transport_send_->OnSentPacket(sent_packet); | 
|  | } | 
|  |  | 
|  | void Call::OnStartRateUpdate(DataRate start_rate) { | 
|  | RTC_DCHECK_RUN_ON(&send_transport_sequence_checker_); | 
|  | bitrate_allocator_->UpdateStartRate(start_rate.bps<uint32_t>()); | 
|  | } | 
|  |  | 
|  | void Call::OnTargetTransferRate(TargetTransferRate msg) { | 
|  | RTC_DCHECK_RUN_ON(&send_transport_sequence_checker_); | 
|  |  | 
|  | uint32_t target_bitrate_bps = msg.target_rate.bps(); | 
|  | // For controlling the rate of feedback messages. | 
|  | receive_side_cc_.OnBitrateChanged(target_bitrate_bps); | 
|  | bitrate_allocator_->OnNetworkEstimateChanged(msg); | 
|  |  | 
|  | last_bandwidth_bps_.store(target_bitrate_bps, std::memory_order_relaxed); | 
|  |  | 
|  | // Ignore updates if bitrate is zero (the aggregate network state is | 
|  | // down) or if we're not sending video. | 
|  | // Using `video_send_streams_empty_` is racy but as the caller can't | 
|  | // reasonably expect synchronize with changes in `video_send_streams_` (being | 
|  | // on `send_transport_sequence_checker`), we can avoid a PostTask this way. | 
|  | if (target_bitrate_bps == 0 || | 
|  | video_send_streams_empty_.load(std::memory_order_relaxed)) { | 
|  | send_stats_.PauseSendAndPacerBitrateCounters(); | 
|  | } else { | 
|  | send_stats_.AddTargetBitrateSample(target_bitrate_bps); | 
|  | } | 
|  | } | 
|  |  | 
|  | void Call::OnAllocationLimitsChanged(BitrateAllocationLimits limits) { | 
|  | RTC_DCHECK_RUN_ON(&send_transport_sequence_checker_); | 
|  |  | 
|  | transport_send_ptr_->SetAllocatedSendBitrateLimits(limits); | 
|  | send_stats_.SetMinAllocatableRate(limits); | 
|  | configured_max_padding_bitrate_bps_.store(limits.max_padding_rate.bps(), | 
|  | std::memory_order_relaxed); | 
|  | } | 
|  |  | 
|  | AudioReceiveStreamImpl* Call::FindAudioStreamForSyncGroup( | 
|  | absl::string_view sync_group) { | 
|  | RTC_DCHECK_RUN_ON(worker_thread_); | 
|  | RTC_DCHECK_RUN_ON(&receive_11993_checker_); | 
|  | if (!sync_group.empty()) { | 
|  | for (AudioReceiveStreamImpl* stream : audio_receive_streams_) { | 
|  | if (stream->sync_group() == sync_group) | 
|  | return stream; | 
|  | } | 
|  | } | 
|  |  | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | void Call::ConfigureSync(absl::string_view sync_group) { | 
|  | // TODO(bugs.webrtc.org/11993): Expect to be called on the network thread. | 
|  | RTC_DCHECK_RUN_ON(worker_thread_); | 
|  | // `audio_stream` may be nullptr when clearing the audio stream for a group. | 
|  | AudioReceiveStreamImpl* audio_stream = | 
|  | FindAudioStreamForSyncGroup(sync_group); | 
|  |  | 
|  | size_t num_synced_streams = 0; | 
|  | for (VideoReceiveStream2* video_stream : video_receive_streams_) { | 
|  | if (video_stream->sync_group() != sync_group) | 
|  | continue; | 
|  | ++num_synced_streams; | 
|  | // TODO(bugs.webrtc.org/4762): Support synchronizing more than one A/V pair. | 
|  | // Attempting to sync more than one audio/video pair within the same sync | 
|  | // group is not supported in the current implementation. | 
|  | // Only sync the first A/V pair within this sync group. | 
|  | if (num_synced_streams == 1) { | 
|  | // sync_audio_stream may be null and that's ok. | 
|  | video_stream->SetSync(audio_stream); | 
|  | } else { | 
|  | video_stream->SetSync(nullptr); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void Call::DeliverRtcpPacket(rtc::CopyOnWriteBuffer packet) { | 
|  | RTC_DCHECK_RUN_ON(worker_thread_); | 
|  | RTC_DCHECK(IsRtcpPacket(packet)); | 
|  | TRACE_EVENT0("webrtc", "Call::DeliverRtcp"); | 
|  |  | 
|  | receive_stats_.AddReceivedRtcpBytes(static_cast<int>(packet.size())); | 
|  | bool rtcp_delivered = false; | 
|  | for (VideoReceiveStream2* stream : video_receive_streams_) { | 
|  | if (stream->DeliverRtcp(packet.cdata(), packet.size())) | 
|  | rtcp_delivered = true; | 
|  | } | 
|  |  | 
|  | for (AudioReceiveStreamImpl* stream : audio_receive_streams_) { | 
|  | stream->DeliverRtcp(packet.cdata(), packet.size()); | 
|  | rtcp_delivered = true; | 
|  | } | 
|  |  | 
|  | for (VideoSendStream* stream : video_send_streams_) { | 
|  | stream->DeliverRtcp(packet.cdata(), packet.size()); | 
|  | rtcp_delivered = true; | 
|  | } | 
|  |  | 
|  | for (auto& kv : audio_send_ssrcs_) { | 
|  | kv.second->DeliverRtcp(packet.cdata(), packet.size()); | 
|  | rtcp_delivered = true; | 
|  | } | 
|  |  | 
|  | if (rtcp_delivered) { | 
|  | event_log_->Log(std::make_unique<RtcEventRtcpPacketIncoming>(packet)); | 
|  | } | 
|  | } | 
|  |  | 
|  | void Call::DeliverRtpPacket( | 
|  | MediaType media_type, | 
|  | RtpPacketReceived packet, | 
|  | OnUndemuxablePacketHandler undemuxable_packet_handler) { | 
|  | RTC_DCHECK_RUN_ON(worker_thread_); | 
|  | RTC_DCHECK(packet.arrival_time().IsFinite()); | 
|  |  | 
|  | if (receive_time_calculator_) { | 
|  | int64_t packet_time_us = packet.arrival_time().us(); | 
|  | // Repair packet_time_us for clock resets by comparing a new read of | 
|  | // the same clock (TimeUTCMicros) to a monotonic clock reading. | 
|  | packet_time_us = receive_time_calculator_->ReconcileReceiveTimes( | 
|  | packet_time_us, rtc::TimeUTCMicros(), clock_->TimeInMicroseconds()); | 
|  | packet.set_arrival_time(Timestamp::Micros(packet_time_us)); | 
|  | } | 
|  |  | 
|  | NotifyBweOfReceivedPacket(packet, media_type); | 
|  |  | 
|  | event_log_->Log(std::make_unique<RtcEventRtpPacketIncoming>(packet)); | 
|  | if (media_type != MediaType::AUDIO && media_type != MediaType::VIDEO) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | RtpStreamReceiverController& receiver_controller = | 
|  | media_type == MediaType::AUDIO ? audio_receiver_controller_ | 
|  | : video_receiver_controller_; | 
|  |  | 
|  | if (!receiver_controller.OnRtpPacket(packet)) { | 
|  | // Demuxing failed.  Allow the caller to create a | 
|  | // receive stream in order to handle unsignalled SSRCs and try again. | 
|  | // Note that we dont want to call NotifyBweOfReceivedPacket twice per | 
|  | // packet. | 
|  | if (!undemuxable_packet_handler(packet)) { | 
|  | return; | 
|  | } | 
|  | if (!receiver_controller.OnRtpPacket(packet)) { | 
|  | RTC_LOG(LS_INFO) << "Failed to demux packet " << packet.Ssrc(); | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | // RateCounters expect input parameter as int, save it as int, | 
|  | // instead of converting each time it is passed to RateCounter::Add below. | 
|  | int length = static_cast<int>(packet.size()); | 
|  | if (media_type == MediaType::AUDIO) { | 
|  | receive_stats_.AddReceivedAudioBytes(length, packet.arrival_time()); | 
|  | } | 
|  | if (media_type == MediaType::VIDEO) { | 
|  | receive_stats_.AddReceivedVideoBytes(length, packet.arrival_time()); | 
|  | } | 
|  | } | 
|  |  | 
|  | void Call::NotifyBweOfReceivedPacket(const RtpPacketReceived& packet, | 
|  | MediaType media_type) { | 
|  | RTC_DCHECK_RUN_ON(worker_thread_); | 
|  |  | 
|  | ReceivedPacket packet_msg; | 
|  | packet_msg.size = DataSize::Bytes(packet.payload_size()); | 
|  | packet_msg.receive_time = packet.arrival_time(); | 
|  | uint32_t time_24; | 
|  | if (packet.GetExtension<AbsoluteSendTime>(&time_24)) { | 
|  | packet_msg.send_time = AbsoluteSendTime::ToTimestamp(time_24); | 
|  | } | 
|  | transport_send_->OnReceivedPacket(packet_msg); | 
|  |  | 
|  | receive_side_cc_.OnReceivedPacket(packet, media_type); | 
|  | } | 
|  |  | 
|  | }  // namespace internal | 
|  |  | 
|  | }  // namespace webrtc |