1 /*
2 * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "modules/rtp_rtcp/source/source_tracker.h"
12
13 #include <algorithm>
14 #include <utility>
15
16 #include "rtc_base/trace_event.h"
17
18 namespace webrtc {
19
20 constexpr int64_t SourceTracker::kTimeoutMs;
21
SourceTracker(Clock * clock)22 SourceTracker::SourceTracker(Clock* clock) : clock_(clock) {}
23
OnFrameDelivered(const RtpPacketInfos & packet_infos)24 void SourceTracker::OnFrameDelivered(const RtpPacketInfos& packet_infos) {
25 if (packet_infos.empty()) {
26 return;
27 }
28
29 TRACE_EVENT0("webrtc", "SourceTracker::OnFrameDelivered");
30
31 int64_t now_ms = clock_->TimeInMilliseconds();
32 MutexLock lock_scope(&lock_);
33
34 for (const RtpPacketInfo& packet_info : packet_infos) {
35 for (uint32_t csrc : packet_info.csrcs()) {
36 SourceKey key(RtpSourceType::CSRC, csrc);
37 SourceEntry& entry = UpdateEntry(key);
38
39 entry.timestamp_ms = now_ms;
40 entry.audio_level = packet_info.audio_level();
41 entry.absolute_capture_time = packet_info.absolute_capture_time();
42 entry.local_capture_clock_offset =
43 packet_info.local_capture_clock_offset();
44 entry.rtp_timestamp = packet_info.rtp_timestamp();
45 }
46
47 SourceKey key(RtpSourceType::SSRC, packet_info.ssrc());
48 SourceEntry& entry = UpdateEntry(key);
49
50 entry.timestamp_ms = now_ms;
51 entry.audio_level = packet_info.audio_level();
52 entry.absolute_capture_time = packet_info.absolute_capture_time();
53 entry.local_capture_clock_offset = packet_info.local_capture_clock_offset();
54 entry.rtp_timestamp = packet_info.rtp_timestamp();
55 }
56
57 PruneEntries(now_ms);
58 }
59
GetSources() const60 std::vector<RtpSource> SourceTracker::GetSources() const {
61 std::vector<RtpSource> sources;
62
63 int64_t now_ms = clock_->TimeInMilliseconds();
64 MutexLock lock_scope(&lock_);
65
66 PruneEntries(now_ms);
67
68 for (const auto& pair : list_) {
69 const SourceKey& key = pair.first;
70 const SourceEntry& entry = pair.second;
71
72 sources.emplace_back(
73 entry.timestamp_ms, key.source, key.source_type, entry.rtp_timestamp,
74 RtpSource::Extensions{
75 .audio_level = entry.audio_level,
76 .absolute_capture_time = entry.absolute_capture_time,
77 .local_capture_clock_offset = entry.local_capture_clock_offset});
78 }
79
80 return sources;
81 }
82
UpdateEntry(const SourceKey & key)83 SourceTracker::SourceEntry& SourceTracker::UpdateEntry(const SourceKey& key) {
84 // We intentionally do |find() + emplace()|, instead of checking the return
85 // value of `emplace()`, for performance reasons. It's much more likely for
86 // the key to already exist than for it not to.
87 auto map_it = map_.find(key);
88 if (map_it == map_.end()) {
89 // Insert a new entry at the front of the list.
90 list_.emplace_front(key, SourceEntry());
91 map_.emplace(key, list_.begin());
92 } else if (map_it->second != list_.begin()) {
93 // Move the old entry to the front of the list.
94 list_.splice(list_.begin(), list_, map_it->second);
95 }
96
97 return list_.front().second;
98 }
99
PruneEntries(int64_t now_ms) const100 void SourceTracker::PruneEntries(int64_t now_ms) const {
101 int64_t prune_ms = now_ms - kTimeoutMs;
102
103 while (!list_.empty() && list_.back().second.timestamp_ms < prune_ms) {
104 map_.erase(list_.back().first);
105 list_.pop_back();
106 }
107 }
108
109 } // namespace webrtc
110