/* * 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 #include "rtc_base/trace_event.h" namespace webrtc { SourceTracker::SourceTracker(Clock* clock) : worker_thread_(TaskQueueBase::Current()), clock_(clock) { RTC_DCHECK(worker_thread_); RTC_DCHECK(clock_); } void SourceTracker::OnFrameDelivered(RtpPacketInfos packet_infos) { if (packet_infos.empty()) { return; } Timestamp now = clock_->CurrentTime(); worker_thread_->PostTask( SafeTask(worker_safety_.flag(), [this, packet_infos = std::move(packet_infos), now]() { RTC_DCHECK_RUN_ON(worker_thread_); OnFrameDeliveredInternal(now, packet_infos); })); } void SourceTracker::OnFrameDeliveredInternal( Timestamp now, const RtpPacketInfos& packet_infos) { TRACE_EVENT0("webrtc", "SourceTracker::OnFrameDelivered"); for (const RtpPacketInfo& packet_info : packet_infos) { for (uint32_t csrc : packet_info.csrcs()) { SourceKey key(RtpSourceType::CSRC, csrc); SourceEntry& entry = UpdateEntry(key); const auto packet_time = packet_info.receive_time(); entry.timestamp = packet_time.ms() ? packet_time : now; entry.audio_level = packet_info.audio_level(); entry.absolute_capture_time = packet_info.absolute_capture_time(); entry.local_capture_clock_offset = packet_info.local_capture_clock_offset(); entry.rtp_timestamp = packet_info.rtp_timestamp(); } SourceKey key(RtpSourceType::SSRC, packet_info.ssrc()); SourceEntry& entry = UpdateEntry(key); entry.timestamp = now; entry.audio_level = packet_info.audio_level(); entry.absolute_capture_time = packet_info.absolute_capture_time(); entry.local_capture_clock_offset = packet_info.local_capture_clock_offset(); entry.rtp_timestamp = packet_info.rtp_timestamp(); } PruneEntries(now); } std::vector SourceTracker::GetSources() const { RTC_DCHECK_RUN_ON(worker_thread_); PruneEntries(clock_->CurrentTime()); std::vector sources; for (const auto& pair : list_) { const SourceKey& key = pair.first; const SourceEntry& entry = pair.second; sources.emplace_back( entry.timestamp, key.source, key.source_type, entry.rtp_timestamp, RtpSource::Extensions{ .audio_level = entry.audio_level, .absolute_capture_time = entry.absolute_capture_time, .local_capture_clock_offset = entry.local_capture_clock_offset}); } std::sort(sources.begin(), sources.end(), [](const auto &a, const auto &b){ return a.timestamp().ms() > b.timestamp().ms(); }); 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(Timestamp now) const { Timestamp prune = now - kTimeout; while (!list_.empty() && list_.back().second.timestamp < prune) { map_.erase(list_.back().first); list_.pop_back(); } } } // namespace webrtc