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