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 namespace webrtc {
17
18 constexpr int64_t SourceTracker::kTimeoutMs;
19
SourceTracker(Clock * clock)20 SourceTracker::SourceTracker(Clock* clock) : clock_(clock) {}
21
OnFrameDelivered(const RtpPacketInfos & packet_infos)22 void SourceTracker::OnFrameDelivered(const RtpPacketInfos& packet_infos) {
23 if (packet_infos.empty()) {
24 return;
25 }
26
27 int64_t now_ms = clock_->TimeInMilliseconds();
28 MutexLock lock_scope(&lock_);
29
30 for (const auto& packet_info : packet_infos) {
31 for (uint32_t csrc : packet_info.csrcs()) {
32 SourceKey key(RtpSourceType::CSRC, csrc);
33 SourceEntry& entry = UpdateEntry(key);
34
35 entry.timestamp_ms = now_ms;
36 entry.audio_level = packet_info.audio_level();
37 entry.absolute_capture_time = packet_info.absolute_capture_time();
38 entry.rtp_timestamp = packet_info.rtp_timestamp();
39 }
40
41 SourceKey key(RtpSourceType::SSRC, packet_info.ssrc());
42 SourceEntry& entry = UpdateEntry(key);
43
44 entry.timestamp_ms = now_ms;
45 entry.audio_level = packet_info.audio_level();
46 entry.absolute_capture_time = packet_info.absolute_capture_time();
47 entry.rtp_timestamp = packet_info.rtp_timestamp();
48 }
49
50 PruneEntries(now_ms);
51 }
52
GetSources() const53 std::vector<RtpSource> SourceTracker::GetSources() const {
54 std::vector<RtpSource> sources;
55
56 int64_t now_ms = clock_->TimeInMilliseconds();
57 MutexLock lock_scope(&lock_);
58
59 PruneEntries(now_ms);
60
61 for (const auto& pair : list_) {
62 const SourceKey& key = pair.first;
63 const SourceEntry& entry = pair.second;
64
65 sources.emplace_back(
66 entry.timestamp_ms, key.source, key.source_type, entry.rtp_timestamp,
67 RtpSource::Extensions{entry.audio_level, entry.absolute_capture_time});
68 }
69
70 return sources;
71 }
72
UpdateEntry(const SourceKey & key)73 SourceTracker::SourceEntry& SourceTracker::UpdateEntry(const SourceKey& key) {
74 // We intentionally do |find() + emplace()|, instead of checking the return
75 // value of |emplace()|, for performance reasons. It's much more likely for
76 // the key to already exist than for it not to.
77 auto map_it = map_.find(key);
78 if (map_it == map_.end()) {
79 // Insert a new entry at the front of the list.
80 list_.emplace_front(key, SourceEntry());
81 map_.emplace(key, list_.begin());
82 } else if (map_it->second != list_.begin()) {
83 // Move the old entry to the front of the list.
84 list_.splice(list_.begin(), list_, map_it->second);
85 }
86
87 return list_.front().second;
88 }
89
PruneEntries(int64_t now_ms) const90 void SourceTracker::PruneEntries(int64_t now_ms) const {
91 int64_t prune_ms = now_ms - kTimeoutMs;
92
93 while (!list_.empty() && list_.back().second.timestamp_ms < prune_ms) {
94 map_.erase(list_.back().first);
95 list_.pop_back();
96 }
97 }
98
99 } // namespace webrtc
100