webrtc/modules/rtp_rtcp/source/source_tracker.cc
Tommi cde4b67d9d [SourceTracker] Move state to the worker thread, remove mutex.
This is in preparation of using the state that SourceTracker manages
for more things than only getContributingSources. Audio levels reported
via getStats(), aren't consistent with levels reported via getCS.

Since more operations will be derived from the ST owned data, moving
the management of it away from the audio thread, reduces the potential
of contention.

Bug: webrtc:14029, webrtc:7517, webrtc:15119
Change-Id: I553f7e473316a1c61eeb43ded905a18242a04424
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/302280
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Commit-Queue: Tomas Gunnarsson <tommi@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#39943}
2023-04-25 08:18:42 +00:00

117 lines
3.7 KiB
C++

/*
* 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 <algorithm>
#include <utility>
#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);
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();
}
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<RtpSource> SourceTracker::GetSources() const {
RTC_DCHECK_RUN_ON(worker_thread_);
PruneEntries(clock_->CurrentTime());
std::vector<RtpSource> sources;
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{
.audio_level = entry.audio_level,
.absolute_capture_time = entry.absolute_capture_time,
.local_capture_clock_offset = entry.local_capture_clock_offset});
}
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