OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2016 The WebRTC Project Authors. All rights reserved. | 2 * Copyright 2016 The WebRTC Project Authors. All rights reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include "webrtc/stats/rtcstatscollector.h" | 11 #include "webrtc/stats/rtcstatscollector.h" |
12 | 12 |
13 #include <memory> | 13 #include <memory> |
14 #include <utility> | 14 #include <utility> |
15 #include <vector> | 15 #include <vector> |
16 | 16 |
17 #include "webrtc/api/peerconnection.h" | 17 #include "webrtc/api/peerconnection.h" |
18 #include "webrtc/base/checks.h" | 18 #include "webrtc/base/checks.h" |
19 #include "webrtc/base/timing.h" | 19 #include "webrtc/base/timing.h" |
20 | 20 |
21 namespace webrtc { | 21 namespace webrtc { |
22 | 22 |
23 RTCStatsCollector::RTCStatsCollector( | 23 rtc::scoped_refptr<RTCStatsCollector> RTCStatsCollector::Create( |
24 PeerConnection* pc, | 24 PeerConnection* pc, int64_t cache_lifetime_us) { |
25 int64_t cache_lifetime_us) | 25 return rtc::scoped_refptr<RTCStatsCollector>( |
| 26 new rtc::RefCountedObject<RTCStatsCollector>(pc, cache_lifetime_us)); |
| 27 } |
| 28 |
| 29 RTCStatsCollector::RTCStatsCollector(PeerConnection* pc, |
| 30 int64_t cache_lifetime_us) |
26 : pc_(pc), | 31 : pc_(pc), |
| 32 signaling_thread_(pc->session()->signaling_thread()), |
| 33 worker_thread_(pc->session()->worker_thread()), |
| 34 network_thread_(pc->session()->network_thread()), |
| 35 num_pending_partial_reports_(0), |
| 36 partial_report_timestamp_us_(0), |
27 cache_timestamp_us_(0), | 37 cache_timestamp_us_(0), |
28 cache_lifetime_us_(cache_lifetime_us) { | 38 cache_lifetime_us_(cache_lifetime_us) { |
29 RTC_DCHECK(pc_); | 39 RTC_DCHECK(pc_); |
30 RTC_DCHECK(IsOnSignalingThread()); | 40 RTC_DCHECK(signaling_thread_); |
| 41 RTC_DCHECK(worker_thread_); |
| 42 RTC_DCHECK(network_thread_); |
31 RTC_DCHECK_GE(cache_lifetime_us_, 0); | 43 RTC_DCHECK_GE(cache_lifetime_us_, 0); |
32 } | 44 } |
33 | 45 |
34 rtc::scoped_refptr<const RTCStatsReport> RTCStatsCollector::GetStatsReport() { | 46 void RTCStatsCollector::GetStatsReport( |
35 RTC_DCHECK(IsOnSignalingThread()); | 47 rtc::scoped_refptr<RTCStatsCollectorCallback> callback) { |
| 48 RTC_DCHECK(signaling_thread_->IsCurrent()); |
| 49 RTC_DCHECK(callback); |
| 50 callbacks_.push_back(callback); |
| 51 |
36 // "Now" using a monotonically increasing timer. | 52 // "Now" using a monotonically increasing timer. |
37 int64_t cache_now_us = rtc::TimeMicros(); | 53 int64_t cache_now_us = rtc::TimeMicros(); |
38 if (cached_report_ && | 54 if (cached_report_ && |
39 cache_now_us - cache_timestamp_us_ <= cache_lifetime_us_) { | 55 cache_now_us - cache_timestamp_us_ <= cache_lifetime_us_) { |
40 return cached_report_; | 56 // We have a fresh cached report to deliver. |
| 57 DeliverCachedReport(); |
| 58 } else if (!num_pending_partial_reports_) { |
| 59 // Only start gathering stats if we're not already gathering stats. In the |
| 60 // case of already gathering stats, |callback_| will be invoked when there |
| 61 // are no more pending partial reports. |
| 62 |
| 63 // "Now" using a system clock, relative to the UNIX epoch (Jan 1, 1970, |
| 64 // UTC), in microseconds. The system clock could be modified and is not |
| 65 // necessarily monotonically increasing. |
| 66 int64_t timestamp_us = static_cast<int64_t>( |
| 67 rtc::Timing::WallTimeNow() * rtc::kNumMicrosecsPerSec); |
| 68 |
| 69 num_pending_partial_reports_ = 3; |
| 70 partial_report_timestamp_us_ = cache_now_us; |
| 71 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_, |
| 72 rtc::Bind(&RTCStatsCollector::ProducePartialResultsOnSignalingThread, |
| 73 rtc::scoped_refptr<RTCStatsCollector>(this), timestamp_us)); |
| 74 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, worker_thread_, |
| 75 rtc::Bind(&RTCStatsCollector::ProducePartialResultsOnWorkerThread, |
| 76 rtc::scoped_refptr<RTCStatsCollector>(this), timestamp_us)); |
| 77 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, network_thread_, |
| 78 rtc::Bind(&RTCStatsCollector::ProducePartialResultsOnNetworkThread, |
| 79 rtc::scoped_refptr<RTCStatsCollector>(this), timestamp_us)); |
41 } | 80 } |
42 cache_timestamp_us_ = cache_now_us; | |
43 // "Now" using a system clock, relative to the UNIX epoch (Jan 1, 1970, UTC), | |
44 // in microseconds. The system clock could be modified and is not necessarily | |
45 // monotonically increasing. | |
46 int64_t timestamp_us = static_cast<int64_t>( | |
47 rtc::Timing::WallTimeNow() * rtc::kNumMicrosecsPerSec); | |
48 | |
49 rtc::scoped_refptr<RTCStatsReport> report = RTCStatsReport::Create(); | |
50 report->AddStats(ProducePeerConnectionStats(timestamp_us)); | |
51 | |
52 cached_report_ = report; | |
53 return cached_report_; | |
54 } | 81 } |
55 | 82 |
56 void RTCStatsCollector::ClearCachedStatsReport() { | 83 void RTCStatsCollector::ClearCachedStatsReport() { |
57 RTC_DCHECK(IsOnSignalingThread()); | 84 RTC_DCHECK(signaling_thread_->IsCurrent()); |
58 cached_report_ = nullptr; | 85 cached_report_ = nullptr; |
59 } | 86 } |
60 | 87 |
61 bool RTCStatsCollector::IsOnSignalingThread() const { | 88 void RTCStatsCollector::ProducePartialResultsOnSignalingThread( |
62 return pc_->session()->signaling_thread()->IsCurrent(); | 89 int64_t timestamp_us) { |
| 90 RTC_DCHECK(signaling_thread_->IsCurrent()); |
| 91 rtc::scoped_refptr<RTCStatsReport> report = RTCStatsReport::Create(); |
| 92 |
| 93 report->AddStats(ProducePeerConnectionStats_s(timestamp_us)); |
| 94 |
| 95 AddPartialResults(report); |
| 96 } |
| 97 |
| 98 void RTCStatsCollector::ProducePartialResultsOnWorkerThread( |
| 99 int64_t timestamp_us) { |
| 100 RTC_DCHECK(worker_thread_->IsCurrent()); |
| 101 rtc::scoped_refptr<RTCStatsReport> report = RTCStatsReport::Create(); |
| 102 |
| 103 // TODO(hbos): Gather stats on worker thread. |
| 104 |
| 105 AddPartialResults(report); |
| 106 } |
| 107 |
| 108 void RTCStatsCollector::ProducePartialResultsOnNetworkThread( |
| 109 int64_t timestamp_us) { |
| 110 RTC_DCHECK(network_thread_->IsCurrent()); |
| 111 rtc::scoped_refptr<RTCStatsReport> report = RTCStatsReport::Create(); |
| 112 |
| 113 // TODO(hbos): Gather stats on network thread. |
| 114 |
| 115 AddPartialResults(report); |
| 116 } |
| 117 |
| 118 void RTCStatsCollector::AddPartialResults( |
| 119 const rtc::scoped_refptr<RTCStatsReport>& partial_report) { |
| 120 if (!signaling_thread_->IsCurrent()) { |
| 121 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_, |
| 122 rtc::Bind(&RTCStatsCollector::AddPartialResults_s, |
| 123 rtc::scoped_refptr<RTCStatsCollector>(this), |
| 124 partial_report)); |
| 125 return; |
| 126 } |
| 127 AddPartialResults_s(partial_report); |
| 128 } |
| 129 |
| 130 void RTCStatsCollector::AddPartialResults_s( |
| 131 rtc::scoped_refptr<RTCStatsReport> partial_report) { |
| 132 RTC_DCHECK(signaling_thread_->IsCurrent()); |
| 133 RTC_DCHECK_GT(num_pending_partial_reports_, 0); |
| 134 if (!partial_report_) |
| 135 partial_report_ = partial_report; |
| 136 else |
| 137 partial_report_->TakeMembersFrom(partial_report); |
| 138 --num_pending_partial_reports_; |
| 139 if (!num_pending_partial_reports_) { |
| 140 cache_timestamp_us_ = partial_report_timestamp_us_; |
| 141 cached_report_ = partial_report_; |
| 142 partial_report_ = nullptr; |
| 143 DeliverCachedReport(); |
| 144 } |
| 145 } |
| 146 |
| 147 void RTCStatsCollector::DeliverCachedReport() { |
| 148 RTC_DCHECK(signaling_thread_->IsCurrent()); |
| 149 RTC_DCHECK(!callbacks_.empty()); |
| 150 RTC_DCHECK(cached_report_); |
| 151 for (const rtc::scoped_refptr<RTCStatsCollectorCallback>& callback : |
| 152 callbacks_) { |
| 153 callback->OnStatsDelivered(cached_report_); |
| 154 } |
| 155 callbacks_.clear(); |
63 } | 156 } |
64 | 157 |
65 std::unique_ptr<RTCPeerConnectionStats> | 158 std::unique_ptr<RTCPeerConnectionStats> |
66 RTCStatsCollector::ProducePeerConnectionStats(int64_t timestamp_us) const { | 159 RTCStatsCollector::ProducePeerConnectionStats_s(int64_t timestamp_us) const { |
| 160 RTC_DCHECK(signaling_thread_->IsCurrent()); |
67 // TODO(hbos): If data channels are removed from the peer connection this will | 161 // TODO(hbos): If data channels are removed from the peer connection this will |
68 // yield incorrect counts. Address before closing crbug.com/636818. See | 162 // yield incorrect counts. Address before closing crbug.com/636818. See |
69 // https://w3c.github.io/webrtc-stats/webrtc-stats.html#pcstats-dict*. | 163 // https://w3c.github.io/webrtc-stats/webrtc-stats.html#pcstats-dict*. |
70 uint32_t data_channels_opened = 0; | 164 uint32_t data_channels_opened = 0; |
71 const std::vector<rtc::scoped_refptr<DataChannel>>& data_channels = | 165 const std::vector<rtc::scoped_refptr<DataChannel>>& data_channels = |
72 pc_->sctp_data_channels(); | 166 pc_->sctp_data_channels(); |
73 for (const rtc::scoped_refptr<DataChannel>& data_channel : data_channels) { | 167 for (const rtc::scoped_refptr<DataChannel>& data_channel : data_channels) { |
74 if (data_channel->state() == DataChannelInterface::kOpen) | 168 if (data_channel->state() == DataChannelInterface::kOpen) |
75 ++data_channels_opened; | 169 ++data_channels_opened; |
76 } | 170 } |
77 // There is always just one |RTCPeerConnectionStats| so its |id| can be a | 171 // There is always just one |RTCPeerConnectionStats| so its |id| can be a |
78 // constant. | 172 // constant. |
79 std::unique_ptr<RTCPeerConnectionStats> stats( | 173 std::unique_ptr<RTCPeerConnectionStats> stats( |
80 new RTCPeerConnectionStats("RTCPeerConnection", timestamp_us)); | 174 new RTCPeerConnectionStats("RTCPeerConnection", timestamp_us)); |
81 stats->data_channels_opened = data_channels_opened; | 175 stats->data_channels_opened = data_channels_opened; |
82 stats->data_channels_closed = static_cast<uint32_t>(data_channels.size()) - | 176 stats->data_channels_closed = static_cast<uint32_t>(data_channels.size()) - |
83 data_channels_opened; | 177 data_channels_opened; |
84 return stats; | 178 return stats; |
85 } | 179 } |
86 | 180 |
87 } // namespace webrtc | 181 } // namespace webrtc |
OLD | NEW |