/* * Copyright (c) 2019 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 "modules/rtp_rtcp/source/source_tracker.h" #include #include namespace webrtc { constexpr int64_t SourceTracker::kTimeoutMs; SourceTracker::SourceTracker(Clock* clock) : clock_(clock) {} void SourceTracker::OnFrameDelivered(const RtpPacketInfos& packet_infos) { if (packet_infos.empty()) { return; } int64_t now_ms = clock_->TimeInMilliseconds(); MutexLock lock_scope(&lock_); for (const auto& packet_info : packet_infos) { for (uint32_t csrc : packet_info.csrcs()) { SourceKey key(RtpSourceType::CSRC, csrc); SourceEntry& entry = UpdateEntry(key); entry.timestamp_ms = now_ms; entry.audio_level = packet_info.audio_level(); entry.absolute_capture_time = packet_info.absolute_capture_time(); entry.rtp_timestamp = packet_info.rtp_timestamp(); } SourceKey key(RtpSourceType::SSRC, packet_info.ssrc()); SourceEntry& entry = UpdateEntry(key); entry.timestamp_ms = now_ms; entry.audio_level = packet_info.audio_level(); entry.absolute_capture_time = packet_info.absolute_capture_time(); entry.rtp_timestamp = packet_info.rtp_timestamp(); } PruneEntries(now_ms); } std::vector SourceTracker::GetSources() const { std::vector sources; int64_t now_ms = clock_->TimeInMilliseconds(); MutexLock lock_scope(&lock_); PruneEntries(now_ms); for (const auto& pair : list_) { const SourceKey& key = pair.first; const SourceEntry& entry = pair.second; sources.emplace_back( entry.timestamp_ms, key.source, key.source_type, entry.rtp_timestamp, RtpSource::Extensions{entry.audio_level, entry.absolute_capture_time}); } return sources; } SourceTracker::SourceEntry& SourceTracker::UpdateEntry(const SourceKey& key) { // We intentionally do |find() + emplace()|, instead of checking the return // value of |emplace()|, for performance reasons. It's much more likely for // the key to already exist than for it not to. auto map_it = map_.find(key); if (map_it == map_.end()) { // Insert a new entry at the front of the list. list_.emplace_front(key, SourceEntry()); map_.emplace(key, list_.begin()); } else if (map_it->second != list_.begin()) { // Move the old entry to the front of the list. list_.splice(list_.begin(), list_, map_it->second); } return list_.front().second; } void SourceTracker::PruneEntries(int64_t now_ms) const { int64_t prune_ms = now_ms - kTimeoutMs; while (!list_.empty() && list_.back().second.timestamp_ms < prune_ms) { map_.erase(list_.back().first); list_.pop_back(); } } } // namespace webrtc